4 ways to import a package to Go

The declarative part of importing packages to Go is quite boring and ordinary. Just need to specify the import directive and list the imported packages. Modern IDEs do this work for you - they themselves put packages into this section, which is very convenient. In addition, they fold this block so that it does not interfere with reviewing the code. I advise you to deploy this unit and study it carefully - maybe you will find something unusual there:


  package main import ( "github.com/vigo5190/goimports-example/a" foo "github.com/vigo5190/goimports-example/a" . "github.com/vigo5190/goimports-example/b" _ "github.com/vigo5190/goimports-example/c" ) 

If standard import, import with a synonym and _ I met, then import with . I have not seen before.


For the beginning it is worth remembering how the programs are run on Go.
The first and most important thing is that in the root of the project (for libraries and packages otherwise) lies the main.go file, which during development is launched by the command


 go run main.go 

A distinctive feature of this file is that the package declared in it must be main .


 package main import ( "fmt" ) func main() { fmt.Println("Hello habr.com!") } 

In essence, the entry point to the program is func main() in the main package. But this behavior can be a little hack . The function func init() invented for this. This function will execute before executing func main() . This function can also be written in your packages. It will always be executed when importing a package (to be precise, it will be executed once the first import of a package in your program). It is also worth understanding that init() will be executed when running the tests of this package.


Package Examples


Package a only exports a variable, but does not initialize it.


github.com/vigo5190/goimports-example/a
 package a var Foo string 

Package b exports the variable and initializes it in init() .


github.com/vigo5190/goimports-example/b
 package b var Foo string func init() { Foo = "bar" } 

Package c exports a variable, initializes it to init() and prints the value to stdout.


github.com/vigo5190/goimports-example/c
 package c import "fmt" var Foo string func init() { Foo = "bar" fmt.Printf("%#v\n", Foo) } 

Import "simple"


In this example, we import 2 packages and output the values ​​of the exported variables to stdout.


 package main import ( "fmt" "github.com/vigo5190/goimports-example/a" "github.com/vigo5190/goimports-example/b" ) func main() { fmt.Printf("%#v\n", a.Foo) fmt.Printf("%#v\n", b.Foo) } 

Will get


 go run main.go "" "bar" 

What actually happens in this code. The import section imports 2 packages a and b . Package a declares a variable with a default value (for strings, an empty string). In the b package, the value of the variable was initialized in init() value "bar" . To access the variables of each package, use the record of the form <_>.<_> .


Import with synonym


 package main import ( "fmt" "github.com/vigo5190/goimports-example/a" foo "github.com/vigo5190/goimports-example/b" bar "github.com/vigo5190/goimports-example/a" ) func main() { fmt.Printf("%#v\n", a.Foo) fmt.Printf("%#v\n", foo.Foo) fmt.Printf("%#v\n", bar.Foo) } 

Will get


 go run main.go "" "bar" "" 

As you can see from the example, package b has the synonym foo . In this case, the package a imported several times - a second time under the pseudonym bar .


Packages are imported using synonyms in several cases:



An example of justified use of a synonym

For example, when importing github.com/sirupsen/logrus :


 package db import( log "github.com/sirupsen/logrus" ) 

Import with underscore


 package main import ( "fmt" "github.com/vigo5190/goimports-example/a" _ "github.com/vigo5190/goimports-example/c" ) func main() { fmt.Printf("%#v\n", a.Foo) } 

Will get


 go run main.go "bar" "" 

As you can see from the code, we import two packages: a and c . In this case, before the c package is _ and in the code itself the package is not used at all. This technique is used to execute init() from the package.


In our example, "bar" appeared in the output on the first line, for the reason that this output is in the initialization function of the package c .


An example of justified use of _

For example, when importing github.com/lib/pq :


 package db import( _ "github.com/lib/pq" ) 

In init() lib/pq such code:


 func init() { sql.Register("postgres", &Driver{}) } 

which will register the driver.


Import c point


 package main import ( "fmt" "github.com/vigo5190/goimports-example/a" . "github.com/vigo5190/goimports-example/b" ) func main() { fmt.Printf("%#v\n", a.Foo) fmt.Printf("%#v\n", Foo) } 

Will get


 go run main.go "" "bar" 

Import with dot adds all exported packet fields to the current scop (more precisely, the file's scope). And now you can work with the fields of the imported package as if they were in your package.


This option should be used very carefully - the example below.


Example 1
 package main import ( . "fmt" ) func main() { Println("Hello, habr.com!") } 

We get:


 Hello, habr.com! 

Example 2
 package main import ( . "fmt" . "math" ) func main() { Printf("%v\n", Sqrt(9)) } 

We get:


 3 

Import c point (and error)


 package main import ( "fmt" . "github.com/vigo5190/goimports-example/a" . "github.com/vigo5190/goimports-example/b" ) func main() { fmt.Printf("%#v\n", Foo) } 

Will get


 go run main.go # command-line-arguments ./main.go:7:2: Foo redeclared during import "github.com/vigo5190/goimports-example/b" previous declaration during import "github.com/vigo5190/goimports-example/a" ./main.go:7:2: imported and not used: "github.com/vigo5190/goimports-example/b" 

As you can see from the output, when importing packages with overlapping fields into the current scope, we get a compilation error.


Therefore, think once again before using such an import - you can get an error completely unexpectedly.


Total


Despite strict syntax restrictions, you can do quite a lot of non-standard things in Go. The above import features show that with just a couple of operators you can greatly change the behavior of the program. The main thing is that using all these opportunities do not shoot yourself in the foot . And remember that it is better to write simple and understandable code than complex and "cool."


PS


Code samples with which it is possible to be played lie on githabe .

Source: https://habr.com/ru/post/413563/


All Articles