将包导入Go的4种方法

将软件包导入Go的声明性部分相当无聊和平凡。 您只需要指定import指令并列出导入的软件包。 现代IDE可以为您完成这项工作-它们本身可以替代本节中的软件包,这非常方便。 另外,它们折叠了此块,以免干扰代码视图。 我建议您扩大此范围并仔细研究-也许您会在这里发现一些不寻常的地方:


  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" ) 

如果是标准导入,请使用同义词和_我遇到,然后从导入. 我没见过


对于初学者来说,值得记住Go程序是如何启动的。
首先也是最重要的事情-在项目的根目录(否则对于库和包)是main.go文件,该文件在开发时由


 go run main.go 

该文件的一个显着特征是其中声明的包必须是main


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

本质上,程序的入口点是main包中的func main() 。 但是,这种行为可以被破解 。 为此,发明了func init()函数。 该函数将在执行func main()之前执行。 此功能也可以写在您的软件包中。 它总是在导入包时执行(准确地说,它将在第一次在程序中导入包时执行)。 还值得理解的是,在运行此程序包的测试时将执行init()


包装实例


a仅导出变量,而不初始化它。


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

b导出变量并将其初始化为init()


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

程序包c导出变量,将其初始化为init()并在stdout中显示该值。


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

导入“简单”


在此示例中,我们导入2个程序包,并将导出的变量的值输出到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) } 

我们得到


 go run main.go "" "bar" 

这段代码实际发生了什么。 在import部分,将import 2个软件包ab 。 在程序包a声明了具有默认值a变量(对于字符串-空字符串)。 在包b ,变量值在init()init()"bar" 。 要访问每个包的变量,请使用<_>.<_>形式的条目。


导入同义词


 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) } 

我们得到


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

从示例中可以看到,为包b分配了同义词foo 。 在这种情况下,包a导入了几次-第二次在别名bar


在几种情况下,可以通过设置同义词来导入包:


  • 导入包的名称不便/丑陋/ ...,我想使用另一个名称;
  • 导入的名称与另一个包的名称相交;
  • 我想无缝替换软件包-软件包接口必须匹配。

正当使用同义词的示例

例如,当导入github.com/sirupsen/logrus


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

下划线导入


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

我们得到


 go run main.go "bar" "" 

如代码所示,我们导入两个包: ac 。 同时,程序包c前面有_ ,并且程序包本身不以任何方式使用。 该技术用于从包中执行init()


在我们的示例中, "bar"出现在第一行的输出中,因为此输出在包初始化函数c


合理使用示例_

例如,当导入github.com/lib/pq


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

init() lib/pq ,代码为:


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

这将注册驱动程序。


导入C点


 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) } 

我们得到


 go run main.go "" "bar" 

带有点的导入会将包的所有导出字段添加到当前作用域(更确切地说是文件作用域)。 现在,您可以像处理导入包中的字段一样使用它们。


应该非常小心地使用此选项-下面是一个示例。


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

我们得到:


 Hello, habr.com! 

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

我们得到:


 3 

带点导入(和错误)


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

我们得到


 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" 

从输出中可以看到,将具有相交字段的包导入当前范围时,会出现编译错误。


因此,在使用这种导入之前,请再三考虑-您可能会完全意外地得到一个错误。


合计


尽管有严格的语法限制,但您仍可以在Go中做很多非标准的事情。 上面讨论的导​​入功能表明,只需几个操作员,您就可以非常改变程序的行为。 在利用所有这些机会时,最主要的是不要向自己开枪 。 请记住,编写简单易懂的代码要比复杂且“酷”的代码更好。


聚苯乙烯


可以使用的代码示例在github上

Source: https://habr.com/ru/post/zh-CN413563/


All Articles