go语言import时为什么都从github导入

上面展示了一些import常用的几种方式但是还有一些特殊的import,让很多新手很费解下面我们来一一讲解一下 到底是怎么一回事

我们有时候会看到如下的方式导入包
这个点操作嘚含义就是这个包导入之后在你调用这个包的函数时,
你可以省略前缀的包名也就是前面你调 
_操作其实是引入该包,而不直接使用包里媔的函数而是调用了该包里面的init函数。
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理服务发现,断路器智...

  • ?开启? 【iAPP实现进入界面执行逐一显】 〖 15:22:14〗 《//首先开一个线程,因...

  • 历代帝王虽多钟无盐只有一名。 齐宣王得钟无盐而成大业历史记载钟无盐四十岁还因为面目丑陋而没有嫁人。 最后因为博...

}

使用包(package)这种语法元素来组织源码所有语法可见性均定义在package这个级别,与Java 、python等语言相比这算不上什么创新,但与C传统的include相比则是显得“先进”了许多。

中包的定義和使用看起来十分简单:

使用import关键字导入要使用的标准库包或第三方依赖包。

但在使用其提供的export functions时却用做前缀包名:

人们不禁要问:import后面路径中的最后一个元素到底代表的是啥? 是包名还是仅仅是一个路径?我们一起通过试验来理解一下  实验环境:darwin_amd64 , go 1.4

初始试验环境目錄结果如下:

我们知道一个非main包在编译后会生成一个.a文件(在临时目录下生成除非使用go install安装到$GOROOT或$GOPATH下,否则你看不到.a)用于后续可执行程序链接使用。

比如Go标准库中的包对应的源码部分路径在:$GOROOT/src而标准库中包编译后的.a文件路径在$GOROOT/pkg/darwin_amd64下。一个奇怪的问题在我脑袋中升腾起来编译时,编译器到底用的是.a还是源码

我们先以用户自定义的package为例做个小实验。

现在我们无法看出使用的到底是foo的源码还是foo.a因为目前咜们的输出都是一致的。我们修改一下foo1.go的代码:

重新编译执行app1我们得到结果如下:

实际测试结果告诉我们:(1)在使用第三方包的时候,当源码和.a均已安装的情况下编译器链接的是源码。

那么是否可以只链接.a不用第三方包源码呢?我们临时删除掉libproj1目录但保留之前install的libproj1/foo.a文件。

我们再次尝试编译app1得到如下错误:

编译器还是去找源码,而不是.a因此我们要依赖第三方包,就必须搞到第三方包的源码这也是Golang包管理的一个特点。

其实通过编译器的详细输出我们也可得出上面结论我们在编译app1时给编译器传入-x -v选项:

可以看到编译器6g首先在临时路径丅编译出依赖包foo.a,放在$WORK/libproj1下但我们在最后6l链接器的执行语句中并未显式看到app1链接的是$WORK/libproj1下的foo.a。但是从6l链接器的-L参数来看:-L $WORK -L

为了验证我们的推論我们按照编译器输出,按顺序手动执行了一遍如上命令但在最后执行6l命令时,去掉了-L $WORK:

编译器链接了$GOPATH/pkg下的foo.a(2)到这里我们明白了所谓嘚使用第三方包源码,实际上是链接了以该最新源码编译的临时目录下的.a文件而已

Go标准库中的包也是这样么?对于标准库比如fmt而言,編译时到底使用的时$GOROOT/src下源码还是$GOROOT/pkg下已经编译好的.a呢?

可以看出编译器的确并未尝试编译标准库中的fmt源码。

从第一节的实验中我们得知了编译器在编译过程中依赖的是包源码的路径,这为后续的实验打下了基础下面我们再来看看,Go语言中import后面路径中最后的一个元素到底是包名还是路径名

按照Golang语言习惯,一个go package的所有源文件放在同一个目录下且该目录名与该包名相同,比如libproj1/foo目录下的package为foofoo1.go、 foo2.go…共同组成foo package嘚源文件。但目录名与包名也可以不同我们就来试试不同的。

注意:这里package名为bar与目录名foo完全不同。

接下来就给app2带来了难题:该如何import bar包呢

我们假设import路径中的最后一个元素是包名,而非路径名

编译失败,在两个路径下无法找到对应libproj2/bar包

我们的假设错了,我们把它改为路徑:

这回编译顺利通过执行结果也是OK的。这样我们得到了结论:(3)import后面的最后一个元素应该是路径就是目录,并非包名

go编译器在这些蕗径(libproj2/foo)下找bar包。这样看来go语言的惯例只是一个特例,即恰好目录名与包名一致罢了也就是说下面例子中的两个foo含义不同:

import中的foo只是一个攵件系统的路径罢了。而下面foo.Foo()中的foo则是包名而这个包是在libproj1/foo目录下的源码中找到的。

再类比一下标准库包fmt

这里上下两行中虽然都是“fmt",泹同样含义不同一个是路径 ,对于标准库来说是$GOROOT/src/fmt这个路径。而第二行中的fmt则是包名gc会在$GOROOT/src/fmt路径下找到fmt包的源文件。

那m到底是包名还是蕗径呢既然能通过m访问Sin,那m肯定是包名了Right!那import m "lib/math"该如何理解呢? 

根据上面一、二两节中得出的结论我们尝试理解一下m:(4)m指代的是lib/math路径丅唯一的那个包

一个目录下是否可以存在两个包呢我们来试试。

我们重新构建一下这个目录下的包:

我们收到了错误提示编译器在這个路径下发现了两个包,这是不允许的

我们再作个实验,来验证我们对m含义的解释

我们建立app3目录,其main.go的源码如下:

libproj2/foo路径下的包的包洺为bar按照我们的推论,m指代的就是bar这个包通过m我们可以访问bar的Bar1导出函数。

编译并执行上面main.go:

执行结果与我们推论完全一致

附录:6g, 6l文檔位置:

}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信