Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Break up go project into subfolders

Tags:

go

I want to break my project up to subfolders.

I want this code structure:

├── main.go
└── models
    └── user.go

Where main.go is:

package main

import (
  "fmt"
  "./models"
)

func main(){
  fmt.Println(User{"new_user"})

}

And user.go is:

package models

type User struct {
  Login string
}

But User is not defined in main package and import raise warning "imported and not used".

What am I doing wrong? My project is simple (not such a example but just with few files (controllers and models)) and I want a simple structure.

Maybe I doing it in completely wrong way?

Problem project is here: https://github.com/abonec/go_import_problem

like image 846
abonec Avatar asked Apr 18 '14 13:04

abonec


2 Answers

I recently achieved this by using go modules.

Golang introduced preliminary opt-in support for modules as of go v1.11.1 which is intended to completely remove the, frankly, absurd $GOPATH necessity. Not only can you now have versioned dependencies in any normal directory such as ~/development, but you can basically have something that looks like namespaces and sub-directories. You can enable this feature by invoking the go command with the following environment variable: GO111MODULE=on.

Go v1.11.3 expects to enable modules by default and is slated for August 2019.


Here is an example directory structure (that you might find typically in some other languages).

~/Dev/my-app
 ├── src/
 │   ├── one/
 │   │   ├── two/
 │   │   │   └── two.go
 │   │   └── one.go
 │   └── zero.go
 ├── go.mod
 └── app.go

The application is called my-app, which will be the module name for app.go. We define this once in go.mod and then each of all the other go files in subdirectories will automatically be importable as if they were namespaced.

Given the above, two.go, assuming it contains a function named Two, will be importable in app.go by using my-app/src/one/two.

Here's what you need to do to achieve this:

go.mod

module my-app

two.go

package two

func Two() string {
    return "I'm totally not supposed to be using go modules for this"
}

app.go

package main

import "my-app/src/one/two"

func main() {
    two.Two()
}

If you were to place another file within two/, then you would simply use two.TheNewFunc() as long as you made TheNewFunc() available within the new file.

I created a very simple GitHub repo which you can check out as a demonstration.

like image 85
Jimbo Avatar answered Nov 15 '22 02:11

Jimbo


Your import should be an absolute one:

import "github.com/abonec/go_import_problem/models"

If you don't want to export your project to an external referential, you can do a:

import "go_import_problem/models"

(That is: "the name of your project folder accessible by GOPATH/your package")

See "How to use custom packages in golang?".

And you would use:

models.User

As mentioned in Effective Go:

The importer of a package will use the name to refer to its contents, so exported names in the package can use that fact to avoid stutter.
(Don't use the import . notation, which can simplify tests that must run outside the package they are testing, but should otherwise be avoided.)


kostix adds in the comments:

to reiterate, names of Go packages are always absolute (that is, there's no relative package names, neither with ./ nor with ../ or anything like that) but that names are "anchored" to one of the so-called workspaces listed in $GOPATH.

When Go searches for a package, it looks through workspaces and tries to find a package in each of them, in order.
The search is not recursive.
And no, there's no requirement to encode URLs in package paths -- unless you want to make your package public.

like image 32
VonC Avatar answered Nov 15 '22 04:11

VonC