Go Keyword import: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(41 intermediate revisions by the same user not shown)
Line 3: Line 3:
* https://golang.org/ref/spec#Import_declarations
* https://golang.org/ref/spec#Import_declarations


=Internal=
=Overview=
 
* [[Go Concepts - Lexical Structure#Keywords|Lexical Structure]]


=Overview=
An import declaration states that the current package depends on the functionality of the imported package and wants access to its name space. Thus, the current package gains access to the [[Go_Language_Modularization#Exported_Identifiers|exported identifiers]] exposed by the imported package.


An import declaration states that the current package depends on the functionality of the imported package and wants access to its name space. Thus, the current package gains access to the [[Go Concepts - Packages#Exported_Identifiers|exported identifiers]] exposed by the imported package.
The import declaration starts with the <tt>import</tt> keyword, optionally followed by a package name alias and mandatory followed by an ''<span id="import_path">import path</span>'' - a string literal that helps the compiler to find the package on the local disk.


<pre>
<pre>
...
...
import [package-name-alias] "package-path-string-literal"
import [package-name-alias] "import-path-string-literal"
...
...
</pre>
</pre>
Line 21: Line 19:
<pre>
<pre>
...
...
import "lib/math"
import "net/http"
import "project1/blue"
...
...
</pre>
</pre>


The <tt>package-name-alias</tt> is optional. If not specified, the package will be referred as the last segment of the path.
The package path (import path) is enclosed in double quotes. It is a [[Go Concepts - Lexical Structure#String_Literal|string literal]]. It is NOT the [[Go_Language_Modularization#Package_Names|package name]], but it helps the compiler to locate the package, instead.
 
The import path represents a local file system path fragment. That path fragment is supposed to live under a <tt>src</tt> directory whose parent is listed in the <tt>[[Go Concepts - Runtime#GOPATH|GOPATH]]</tt> environment variable. Note that if the import path has multiple segments, only the last one represents the package name and can used to prefix identifiers belonging to the imported package, in the program. For example, if we import <tt>import "project1/blue"</tt>, we only use <tt>blue</tt> to qualify identifiers from that package: <tt> blue.DoSomethingBlue()</tt>.
 
=Unused Packages=
 
The compiler will fail whenever it finds an imported packages that is not used. The reason behind this behavior is that we don't want unnecessarily large binaries, that include the code for packages that are not actually used. There are legitimate cases when we need to work around this behavior, and one is when we need to run initialization code from a specific package. See [[#The_Blank_Identifier_When_Importing_a_Package|the blank identifier and package import]].
 
=Importing two Packages with the Same Name=
 
The <tt>package-name-alias</tt> is optional, and it should be used when we have a package name conflict - we're trying to use two package whose terminal path segment is the same. If <tt>package-name-alias</tt> is not specified, the package will be referred as the last segment of the path.
 
The import becomes a ''named import'' if the <tt>package-name-alias</tt> is used.
 
=Importing Multiple Packages=
 
The idiomatic way of importing more than one package:
 
<pre>
import (
    "fmt"
    "strings"
)
</pre>
 
=The Blank Identifier When Importing a Package=
 
 
The [[Go_Concepts_-_Lexical_Structure#The_Blank_Identifier|blank identifier]] "_" can be used to prefix the import path when importing a package when we need that package for its side effects (its <tt>[[Go_Concepts_-_Functions#The_init.28.29_Function|init()]]</tt> function), but we don't use the package identifier anywhere in the source code:
 
<pre>
import _ "some/path/some-package"
</pre>
 
If we simply import the package and we don't use its identifier, we get:
 
<pre>
./example.go:4: imported and not used: "io"
</pre>
 
=Accessing an Identifier from an Imported Package=
 
Once a package has been declared as "imported", all exported identifiers from the imported package are available in the importing package. In order to access an individual exported identifier, the identifier should be prefixed with the name of the package. For example, in order to access the <tt>struct</tt> <tt>Box</tt> exposed by package "pkgA", we do this:
 
<pre>
import "pkgA"
...
func f() {
    ...
    var b pkgA.Box
    ...
}
</pre>


=How Packages are Resolved=
=How Packages are Resolved=

Latest revision as of 21:34, 8 September 2023

External

Overview

An import declaration states that the current package depends on the functionality of the imported package and wants access to its name space. Thus, the current package gains access to the exported identifiers exposed by the imported package.

The import declaration starts with the import keyword, optionally followed by a package name alias and mandatory followed by an import path - a string literal that helps the compiler to find the package on the local disk.

...
import [package-name-alias] "import-path-string-literal"
...

Example

...
import "net/http"
import "project1/blue"
...

The package path (import path) is enclosed in double quotes. It is a string literal. It is NOT the package name, but it helps the compiler to locate the package, instead.

The import path represents a local file system path fragment. That path fragment is supposed to live under a src directory whose parent is listed in the GOPATH environment variable. Note that if the import path has multiple segments, only the last one represents the package name and can used to prefix identifiers belonging to the imported package, in the program. For example, if we import import "project1/blue", we only use blue to qualify identifiers from that package: blue.DoSomethingBlue().

Unused Packages

The compiler will fail whenever it finds an imported packages that is not used. The reason behind this behavior is that we don't want unnecessarily large binaries, that include the code for packages that are not actually used. There are legitimate cases when we need to work around this behavior, and one is when we need to run initialization code from a specific package. See the blank identifier and package import.

Importing two Packages with the Same Name

The package-name-alias is optional, and it should be used when we have a package name conflict - we're trying to use two package whose terminal path segment is the same. If package-name-alias is not specified, the package will be referred as the last segment of the path.

The import becomes a named import if the package-name-alias is used.

Importing Multiple Packages

The idiomatic way of importing more than one package:

import (
    "fmt"
    "strings"
)

The Blank Identifier When Importing a Package

The blank identifier "_" can be used to prefix the import path when importing a package when we need that package for its side effects (its init() function), but we don't use the package identifier anywhere in the source code:

import _ "some/path/some-package"

If we simply import the package and we don't use its identifier, we get:

./example.go:4: imported and not used: "io"

Accessing an Identifier from an Imported Package

Once a package has been declared as "imported", all exported identifiers from the imported package are available in the importing package. In order to access an individual exported identifier, the identifier should be prefixed with the name of the package. For example, in order to access the struct Box exposed by package "pkgA", we do this:

import "pkgA"
...
func f() {
    ...
    var b pkgA.Box
    ...
}

How Packages are Resolved

The algorithm is described here:

GOPATH