Today we have a very important topic…
Import declarations
An import declaration states that the source file containing the declaration depends on functionality of the imported package (§Program initialization and execution) and enables access to exported identifiers of that package. The import names an identifier (PackageName) to be used for access and an ImportPath that specifies the package to be imported.
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) . ImportSpec = [ "." | PackageName ] ImportPath . ImportPath = string_lit .
The PackageName is used in qualified identifiers to access exported identifiers of the package within the importing source file. It is declared in the file block. If the PackageName is omitted, it defaults to the identifier specified in the package clause of the imported package. If an explicit period (
.
) appears instead of a name, all the package’s exported identifiers declared in that package’s package block will be declared in the importing source file’s file block and must be accessed without a qualifier.
This is a good place to stop and parse what we’ve just read.
An import declaration starts with the word import
, followed by one or more import specs. If more than one, the specs must be wrapped in parenthesis. Therefore, following snippets are equivalent:
import "fmt"
import "math"
import (
"fmt"
"math"
)
import (
"fmt"
)
import (
"math"
)
The import spec is where things start to get more interesting. It contains only two parts, but there are some subtleties to consider. Let’s do that by looking at some examples, starting with the simplest.
import foo "example.org/foo"
Here we have an import spec with an explicit package name, and import path. There’s no ambguity here at all. If you want to call function Bar
in the imported package, you do it by using the package name:
foo.Bar( /* ... */ )
But that foo
package name looks redundant, right? Can’t we omit it?
import "example.org/foo"
Short answer: Probably. Long answer: Not so fast! The default package name is taken from the package
clause in the imported package. And while it is convention to name a package the same as the last element of an import path, it’s not required. So if we were to open up the imported package and see the following:
package bar
then this would fail, unless we update foo.Bar
to bar.Bar
:
import "example.org/foo"
main() {
bar.Bar( /* ... */ )
}
Well ain’t that confusing. There’s no way, other than guessing, to determine where that bar
thing comes from. Consider this when naming your packages!
Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)