Relationship between a package statement and the directory of a .go file

If what you said was true, then your function call would actually be 1-foodir.FooFunc() instead of foopkg.FooFunc(). Instead, go sees the package name in 2-foofile.go and imports it as foopkg because in go the name of the package is exactly what comes after the words package at the top of .go files, provided it is a valid identifier.

The only use of the directory is for collecting a set of files that share the same package name. This is reiterated in the spec

A set of files sharing the same PackageName form the implementation of a package. An implementation may require that all source files for a package inhabit the same directory.

In go, it is convention that the directory match the package name but this doesn't have to be the case, and often it is not with 3rd party packages. The stdlib does do a good job of sticking to this convention.

Now where directories do come into play is the import path. You could have 2 packages named 'foo' in your single binary as long as they had different import paths, i.e.

/some/path/1/foo and /some/path/2/foo

And we can get really swanky and alias the imports to whatever we wanted, for example I could do

import (
    bar "/some/path/1/foo"
    baz "/some/path/2/foo"
)

Again the reason this works is not because the package name has to be unique, but the package import path must be unique.

Another bit of insight to glean from this statement is -- within a directory, you cannot have two package names. The go compiler will throw an error stating it cannot load package and that it found packages foo (foo.go) and bar (bar.go).

See https://golang.org/doc/code.html#PackageNames for more information.


First thing first, the package clause and import path are different things.

package clause declares PackageName:

PackageClause  = "package" PackageName .
PackageName    = identifier .

The purpose of a package clause is to group files:

A set of files sharing the same PackageName form the implementation of a package.

By convention, the path basename (directory name) of ImportPath (see below) is the same as PackageName. It's recommended for convenient purposes that you don't need to ponder what's the PackageName to be used.

However, they can be different.

The basename only affects the ImportPath, check spec for import declartions:

ImportDecl       = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec       = [ "." | PackageName ] ImportPath .
ImportPath       = string_lit .

If the PackageName is omitted, it defaults to the identifier specified in the package clause of the imported package.

For example, if you have a dir foo but you declare package bar in a source file resides in it, when you import <prefix>/foo, you will use bar as a prefix to reference any exported symbols from that package.

darehas' answer raises a good point: you can't declare multiple packages under the same basename. However, according to package clause, you can spread the same package over different basenames:

An implementation may require that all source files for a package inhabit the same directory.


Roughly for the why:

  1. Packages have a "name" which is set by the package clause, the package thepackagename at the start of your source code.

  2. Importing packages happens by pretty much opaque strings: the import path in the import declarations.

The first is the name and the second how to find that name. The first is for the programmer, the second for the compiler / the toolchain. It is very convenient (for compilers and programmers) to state

Please import the package found in "/some/hierarchical/location"

and then refer to that package by it's simple name like robot in statements like

robot.MoveTo(3,7)

Note that using this package like

/some/hierarchical/location.MoveTo(3.7)

would not be legal code and neither readable nor clear nor convenient. But to for the compiler / the toolchain it is nice if the import path has structure and allows to express arbitrary package locations, i.e. not only locations in a filesystem, but e.g. inside an archive or on remote machines, or or or.

Also important to note in all this: There is the Go compiler and the go tool. The Go compiler and the go tool are different things and the go tool imposes more restrictions on how you lay out your code, your workspace and your packages than what the Go compiler and the language spec would require. (E.g. the Go compiler allows to compile files from different directories into one package without any problems.)

The go tool mandates that all (there are special cases, I know) your source files of a package reside in one file system directory and common sense mandates that this directory should be "named like the package".

Tags:

Import

Package

Go