33

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

abonec
  • 1,379
  • 1
  • 14
  • 23

6 Answers6

36

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.

Jimbo
  • 25,790
  • 15
  • 86
  • 131
  • 1
    Can you explain the comment in that string there: "I'm totally not supposed to be using go modules for this". What do you mean we're not supposed to use modules for this? – Nathan Lutterman Mar 04 '19 at 21:40
  • @NathanLutterman Before I saw this being common, I naturally assumed purists will hate anything not normally done in Golang. This attitude is very common amongst go programmers. However I can remove this now as it seems it's pretty standard :) – Jimbo Mar 04 '19 at 21:45
  • Is it possible to ```import "my-app/src/one/two"``` inside ```one``` package? – Vahid Alimohamadi Sep 24 '20 at 22:50
  • @cybercoder Are you trying to import multiple packages with one line there? Or just a normal import? – Jimbo Sep 25 '20 at 07:59
  • @Jimbo clearly, i need to import ```two``` package inside ```one``` package in your structure. – Vahid Alimohamadi Sep 25 '20 at 08:18
  • @cybercoder Re-read your sentence, and for the future consider what may be obvious to you may not be others. You put /one/two inside one string - to me that was just a standard import with sub-package 1 followed by sun-package 2. Regardless, no you cannot use ‘PHP-style group namespace imports’ unfortunately. – Jimbo Sep 25 '20 at 08:26
  • this is what i needed and i did create it, i don't know go, but it seems it is working! https://github.com/cybercoder/go3cho – Vahid Alimohamadi Sep 25 '20 at 09:37
  • Is the directory `src` a necessity for this to work? Because to me it seems ugly to have `src` in the import – Jimmy R.T. Jan 13 '21 at 10:17
  • @JimmyR.T. You can place whatever directory structure you want. Some use `internal` which doesn't allow imports for these. I think IDEs work with this too. See: https://stackoverflow.com/questions/41571946/internal-packages-in-go. I use internal now instead of src but really, it doesn't matter *at all*. Use whatever you want or internal as above. – Jimbo Jan 13 '21 at 10:18
  • Also side-note: don't fall into the trap of dogmatically placing all your code in one file, or all in one directory ;) – Jimbo Jan 13 '21 at 10:19
10

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.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    I don't plane to store any of this code in github. What should I do import and change in my project tree? – abonec Apr 18 '14 at 14:31
  • @Abonec then `import "models"` should be enough – VonC Apr 18 '14 at 14:33
  • it don't work and raise cannot find package "models" in any of: /usr/local/go/src/pkg/conf (from $GOROOT) /home/abonec/gopath/src/conf (from $GOPATH) – abonec Apr 18 '14 at 14:41
  • @Abonec did you do a `go build` inside models fist? And then a `go build` in main – VonC Apr 18 '14 at 14:43
  • it does't work. This is one project just broked up into subfolders. – abonec Apr 18 '14 at 14:54
  • @Abonec I have edited my answer with link to more documentation. Try `import "go_import_problem/models"` – VonC Apr 18 '14 at 14:57
  • @Abonec the folder `go_import_problem` where you have your file should be accessible directly under the path referenced by `GOPATH`. – VonC Apr 18 '14 at 14:59
  • my project is standalone. Is that means I should modify GOPATH everytime when I work on that project or want to build it? Not handy way. – abonec Apr 18 '14 at 15:15
  • @Abonec no, your `GOPATH` can be a generic one, under which live the different projects you have. Or you can have several path within your `GOPATH`: `GOPATH=first/path;second/path` (on Windows), or `GOPATH=first/path:second/path` (on Unix) – VonC Apr 18 '14 at 15:16
  • is that means that I should add every of my projects which I work for to GOPATH? – abonec Apr 18 '14 at 15:28
  • @Abonec not if all your projects are all under the same folder (unique folder referenced by `GOPATH`). Each project in its own folder, but all those "project folders" under one common `GOPATH` folder. – VonC Apr 18 '14 at 15:29
  • 1
    @Abonec Remember, a `GOPATH` doesn't reference a project. It references a '**workspace**'. Under each workspace, you can find one or several folders, each of those folders represents a project. – VonC Apr 18 '14 at 15:31
  • is that means I should copy any of my projects into this workspace? It's a bit surprising me because I don't meet with that way in any of others languages where I can "git clone" project into any place in my drive. – abonec Apr 18 '14 at 15:48
  • 1
    @Abonec yes, or you can define several workspaces, under which a subset of your projects can live (since, again, `GOPATH` can list several workspace folders) – VonC Apr 18 '14 at 15:49
  • @Abonec, could you please start with reading [the doc which explains in all](http://golang.org/doc/code.html)? Assuming that if you know `N` programming languages and their ecosystems, you by definition are familiar with the next one is a common fallacy, and Go *is* different in many ways. – kostix Apr 19 '14 at 05:29
  • @Abonec, 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. – kostix Apr 19 '14 at 05:36
  • @kostix good points (again). I have included your comment in the answer for more visibility. – VonC Apr 19 '14 at 05:40
  • Thanks, but I'm afraid the OP discovered the idea of adding "." in their `$GOPATH` which can probably work but is not what the Go authors envisioned. At least that's how I interpret the OP's own answer. – kostix Apr 19 '14 at 06:07
  • @kostix I agree. That is why I quoted the Effective Go passage in the first place. – VonC Apr 19 '14 at 06:08
  • @Abonec, one more note on URLs in package names while we're on it: originally they served only name spacing purposes -- for instance, you can store all the packages for internal use in your enterprise, Acme Inc, under the directory named "acme" (it's believed folks in Google use "google" for this). The idea of encoding URLs of SCM hosting sites came later to support the `go get` tool which is a brilliant no-brainier solution for getting someone else's code. So, if your namespace is an URL, your code is said to "be go-gettable" but it might be just fine if it isn't. – kostix Apr 19 '14 at 06:11
0

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

So

fmt.Println(models.User{"new_user"})
nos
  • 223,662
  • 58
  • 417
  • 506
0

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.

Evan
  • 6,369
  • 1
  • 29
  • 30
  • 2
    my project is not especially large. I just want to break it up to files with 30-50 lines by it domain logic. But I can't undersand how. – abonec Apr 18 '14 at 15:21
  • @Abonec A single package can have multiple files - i.e. server.go, models.go, otherthings.go, handlers.go, etc. These can all be in `package main` if splitting them into subpackages doesn't 'make sense'. – elithrar Apr 18 '14 at 16:07
-1

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.

Darcys22
  • 1,204
  • 2
  • 11
  • 20
  • 1
    This answer might be correct but it is definitely missing details that a Go beginner like me needs. What is a "go/src" folder? Is it some magic location? – Ted Henry Jun 19 '21 at 03:55
-7

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
abonec
  • 1,379
  • 1
  • 14
  • 23
  • 1
    do not use relative imports if you want your project to be used by other's, and fully compatible with the go toolcahin. Always import via the proper package name. – JimB Apr 18 '14 at 13:55
  • @JumB how should I import in this example? – abonec Apr 18 '14 at 14:51
  • via it's proper path in your workspace. see http://golang.org/doc/code.html#Organization – JimB Apr 18 '14 at 15:18