04|初窥门径:一个Go程序的结构是怎样的?
04|初窥门径:一个Go程序的结构是怎样的?
讲述:Tony Bai
时长20:01大小18.29M
创建“hello,world”示例程序
创建“hello,world”文件夹
编写并运行第一个 Go 程序
“hello,world”示例程序的结构
Go 语言中程序是怎么编译的?
复杂项目下 Go 程序的编译是怎样的
小结
思考题
赞 75
提建议
精选留言(80)
- swordholder2021-10-20如何import自己在本地创建的module,在这个module还没有发布到GitHub的情况下?
作者回复: 非常好的问题。go module机制在您提到的工作场景下目前的体验做的还不够好。在Go 1.17版本及之前版本的解决方法是使用go mod的replace指示符(directive)。假如你的module a要import的module b将发布到github.com/user/repo中,那么你可以手动在module的go.mod中的require块中手工加上一条: require github.com/user/repo v1.0.0 注意v1.0.0这个版本号是一个临时的版本号。 然后在module a的go.mod中使用replace将上面对module b的require替换为本地的module b: replace github.com/user/repo v1.0.0 => module b本地路径 这样go命令就会使用你本地正在开发、尚未提交github的module b了。 你可以试试。
共 13 条评论65 - return2021-10-20老师讲的太好了, 重点细节 都很到位,赞啊。 请教老师: 如果 路径和包名不一样, path: apath, package: apack 那么使用的时候是这样吗? import "apath" apack.Print()展开
作者回复: 你的理解非常正确,给你点个赞!
共 2 条评论41 - 多选参数2021-11-14go 引用了其他包的话,是将引用的包都编译进去。我用 ldd 才看几个 go 编译出来的二进制程序都是没有动态链接库的使用。但是,在看其他几个 go 编译出来的二进制程序时(比如 containerd、ctr,它们都是用 go 编写的),又有引用动态链接库,这个是为什么?
作者回复: go默认是开启CGO_ENABLED的,即CGO_ENABLED=1。但编译出来的二进制程序究竟有无动态链接,取决于你的程序使用了什么包。如果就是一个hello,world,那么你编译出来的将是一个纯静态程序。 如果你依赖了网络包或一些系统包,比如用http包编写了一个web server(见第9讲示例),那么你编译出来的二进制程序又会是一个包含动态链接的程序。 原因就在于目前的go标准库中,某些功能具有两份实现,一份是c语言实现的,一份是go语言实现的。在cgo_enable开启的情况下,go链接器会链接c语言的版本,于是就有了依赖动态链接库的情况。如果你将cgo_enabled置为0,你再重新编译链接,那么go链接器会使用go版本的实现,这样你将得到一个没有动态链接的纯静态二进制程序。
共 7 条评论36 - william2021-10-20前面能看懂,后面就开始迷了。。。 Go Module 的概念我还是不怎么理解, 很多教程都用github.com... 做例子, 你说的是”路径“,路径不应该是 (win10)"D:\goprojects\hellomodule" 吗?我自己自定义一个任意的名字也可以正常运行?我感觉很奇怪,为什么很多人用github.com/...做module呢? 还有go mod tidy 命令后,下载的包在哪?在Go语言安装路径的src文件夹中?还是在哪?展开
作者回复: 1. 使用github.com/...作为module path是因为多数实用级module多是上传到github上的。用这种示例便于后续与真实生产接驳。但对于本地开发使用的简单示例程序而言,你说的没错。module path可以任意起,比如: module demo1 也是ok的。 第二个问题,go mod tidy下载的第三方包一般在$GOPATH/pkg/mod下面。如果没有设置GOPATH环境变量,其默认值为你的home路径下的go文件夹。这样第三方包就在go文件夹的pkg/mod下面。
共 4 条评论20 - Hans2021-10-21配置国内镜像代理(使用阿里云镜像) go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/ 验证 go env|grep GOPROXY
作者回复: 嗯,国内的几大goproxy服务都是可以的。
共 4 条评论20 - 自由2021-10-20关于思考题,我认为统一的代码风格是很有必要的。 在多人协作时,我们的代码存放在 git 仓库中,git 的代码提交记录,文件中的缩进和折行也会被视为改动。假如两位同学的格式化风格不同,提交代码时,一个文件中的实际改动与 git 记录的改动将会相差甚远!100 行代码就会多出 100 行改动,而实际上,有效改动可能仅仅是几行代码,在追溯问题时,带来很多不必要的麻烦。展开
作者回复: 作为一个多年gopher的心底话,现在go开发已经完全离不开gofmt或类似工具了。并且这些标准风格格式化工具与各种编辑器或IDE结合后,是在“quiet模式”下帮助开发者,并不需要开发者付出额外的工作量。
17 - lesserror2021-10-20感谢Tony Bai老师这么细致的讲解。能够基于最新的Go Module来讲解,正好是我想要的。 之前看了太多基于go path的教程。感觉Go Module比之前的go path清晰多了。 有几个问题想要了解下: 1. 老师这节课的源码目录为什么不是类似:src/github.com/xxx 这样的方式在本地构建呢? 我看很多地方,建议以这种方式来创建项目。 2. go mod tidy 这个命令中的 tidy 该如何翻译比较准确呢? 这个命令平时还挺常用的,希望结合中文翻译去加深记忆。 ps: 希望后面老师能够,结合Go项目的代码访问路径,来系统讲解一下,代码的访问流程。展开
作者回复: 问题1:go module与gopath的一个重要区别就是可以将项目放在任意路径下,而无需局限在$GOPATH/src下面。我之所以将一个module放在一个任意路径下,就是故意要与GOPATH模式区分开的。 问题2:有些时候,无论怎么翻译都不能很理想的呈现英文作者的原意,因此向go mod tidy我倾向于直接使用原文,而不要翻译为中文。 关于你的建议,我后续会重点考虑的,感谢。
共 4 条评论14 - 隰有荷2021-11-05老师,我有些不理解的地方在于: 1、 1-1、go mod init 后面跟的路径规则是什么样的? 1-2、这个命令本身是什么含义? 1-3、文中所说的module,到底哪个是module,是go.mod文件是module,还是hellomodule这个文件夹是module?因为我看文章中说当前文件夹是module的根目录,所以这里不太理解。 2、我在执行go mod tidy 之后出现报错:go: warning: "all" matched no packages。但是我每一步都和文章中的步骤一样,请问是哪里出现了问题?展开
作者回复: 1-1. go mod init后面的路径就是go.mod中module后面的路径,代表的是module path。 1-2. go mod init命令的实际行为就是在当前目录下创建一个go.mod,而这个go.mod将当前目录转换为一个go module。 1-3. go module是一个逻辑概念。文中也说了,它更像一个命名空间的概念。它与文件夹名称无关。有了go.mod后,这个文件夹下的各个包就算是这个go module下面的包了。包的导入路径也是以module path为前缀的。 2. 确认一下你本地的go编译器版本?确认go module构建模式已开启。确认一下是否在go.mod所在目录执行的go mod tidy?
10 - Demon.Lee2021-10-26如果与面向对象语言进行类比,go 语言中的包,是否可以类比成Java中的类呢?
作者回复: 如果从编译的角度来讲,go包是编译的基本单位,每个go包编译为一个.a文件,每个java public class编译为一个class文件。它们的确有些类似。但从内容结构上来说,go包是一个命名空间的概念,可以包含go所有语法元素。java class就是一个拥有多个属性+方法的抽象。
7 - 进化菌2021-10-25Go 的文件名原来不偏好下划线连接,细节~ Go 的编译,看起来比解析型的语言麻烦,但是跑起来之后,感觉像是打开了一扇大门。6
- Rayjun2021-10-20老师,提个问题,有了 Go Module 之后, GoPath 还有存在的必要么?
作者回复: go官方有移除gopath的打算。目前这个时间点,学习go基本不需要了解太多gopath了。
共 2 条评论6 - GAC·DU2021-10-20Go编译模式很好的解决了环境问题,就像docker镜像一样,一包在手,天下可跑,不再需要考虑环境的问题,实现了宏观上的标准化。不过有一个疑惑,如果一个大项目需要引用很多外部项目,编译的包会不会过大,因此不利于项目的分发部署?
作者回复: 无论任何静态编程语言,引用外部依赖越多,最终编译生成的可执行文件size都会越大。毕竟要把真正依赖的包的目标代码放入可执行文件中。这个没招啊。
共 3 条评论6 - aoe2021-10-20Go Module看起来很好用啊!
作者回复: go module已经是go官方标准包依赖管理和构建模式了,所以从go入门开始就建议直接使用go module。gopath模式可以简单了解一下,然后忽略掉就好了。
共 2 条评论5 - tequ1lAneio2021-10-20风格统一的确会给团队协作带来的极大的便利,但同时也会导致一部分人因为厌恶统一后的代码风格选择离开。
作者回复: 感觉风格统一是未来编程语言的大趋势。很高兴你留在了go阵营:)
共 2 条评论4 - Aeins2022-05-24go.mod 文件中 module 指令设置模块的模块路径,可以是任意的,不需要和文件系统对应。建议和项目目录名相同 包的导入路径为模块路径和相对模块根目录(go.mod所在目录)的相对路径组成 包名由 package 语句指定,建议和包的目录名相同(也可以不同) 模块和包都对应了一个文件系统目录展开
作者回复: 👍
3 - William Ning2022-02-17文章与评论看完,感觉收获不少。
作者回复: 👍
3 - Vettel2021-12-30个人觉得代码格式的统一是很好的,就拿Java的import的来说,有人喜欢import * 有人不喜欢,就单纯一个import就可能浪费很多解决代码冲突的时间
作者回复: 👍
3 - holly2021-11-02老师,您好,我是本地构建的,在helloworld的上一级目录执行, go mod init helloworld,再执行go mod tidy,看输出下载了很多依赖包 go: finding module for package go.uber.org/zap go: finding module for package github.com/valyala/fasthttp go: downloading go.uber.org/zap v1.19.1 go: downloading github.com/valyala/fasthttp v1.31.0 go: found github.com/valyala/fasthttp in github.com/valyala/fasthttp v1.31.0 go: found go.uber.org/zap in go.uber.org/zap v1.19.1 go: downloading github.com/andybalholm/brotli v1.0.2 go: downloading github.com/klauspost/compress v1.13.4 go: downloading github.com/valyala/bytebufferpool v1.0.0 go: downloading go.uber.org/atomic v1.7.0 go: downloading go.uber.org/multierr v1.6.0 go: downloading github.com/pkg/errors v0.8.1 go: downloading github.com/stretchr/testify v1.7.0 go: downloading go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 go: downloading github.com/benbjohnson/clock v1.1.0 go: downloading gopkg.in/yaml.v2 v2.2.8 go: downloading github.com/davecgh/go-spew v1.1.1 go: downloading github.com/pmezard/go-difflib v1.0.0 go: downloading gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b go.mod 中内容也多出几个 module helloworld go 1.17 require ( github.com/valyala/fasthttp v1.31.0 go.uber.org/zap v1.19.1 ) require ( github.com/andybalholm/brotli v1.0.2 // indirect github.com/klauspost/compress v1.13.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect ) 不知有没有跟我一样的同学展开
作者回复: go 1.17会将indirect依赖都列出来,与Go 1.16不同。
共 2 条评论3 - cheriston2021-10-21-a---- 2021/10/20 13:21 233 continue使用.go -a---- 2021/10/21 11:13 95 go.mod -a---- 2021/10/21 11:13 6924 go.sum -a---- 2021/10/21 11:15 6414336 main.exe -a---- 2021/10/20 17:51 343 main.go -a---- 2021/10/20 16:10 102 随机数.go PS C:\Go_WorkSpace\src\ch3> .\main.exe 老师 卡主了,没答案了展开
作者回复: 这个是一个http server,需要向它发一个请求才能有输出哦。文稿里有说明。
3 - 不负青春不负己🤘2021-10-21文中关于 import 表示就是fmt目录,而fmt.Printf 代表是 fmt包,同一个目录下的同级的所有go文件应该属于一个包,包的名称可以跟目录不同名,不过建议同名;3