abonec
abonec

Reputation: 1431

Break up go project into subfolders

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

Upvotes: 35

Views: 43096

Answers (6)

Darcys22
Darcys22

Reputation: 1234

The packages are referenced in code in relation to your "go/src" folder

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

So in main.go

package main

import (
  "fmt"
  "myAwesomeProject/models"
)

Similarly packages can reference each other using the same convention.

Upvotes: -1

Jimbo
Jimbo

Reputation: 26624

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.

Upvotes: 37

VonC
VonC

Reputation: 1328602

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.

Upvotes: 11

Evan
Evan

Reputation: 6545

Breaking up a single project into subfolders is not the recommended way of structuring a go project, which is why there is basically no good way to do what you want.

If the project is really large, and too unwieldy to make a single package, consider splitting it into several totally distinct packages, rather than special sub-directory packages. This has the advantage of forcing you to think cleanly about your internal APIs.

Upvotes: 0

nos
nos

Reputation: 229284

You need to qualify items in in a package by its package name

So

fmt.Println(models.User{"new_user"})

Upvotes: 0

abonec
abonec

Reputation: 1431

You should use your imported objects by it's imported names. For example if you

import "./models"

with struct User you should use it as

models.User

Upvotes: -7

Related Questions