04|初窥门径:一个Go程序的结构是怎样的?

Go 入门笔记 | 极客时间 | 《Tony Bai · Go语言第一课》目录

原文

摘要

  • go help
  • go mod init [module-path]
    • 在当前目录初始化一个go模块,创建 go.mod 和 go.sum
    • 创建前 go.mod 不能存在
    • Example:
      • go mod init
      • go mod init github.com/tonybai8/go-notes/go-notes
  • go mod tidy [-e] [-v] [-go=version] [-compat=version]
    • 自动获取添加依赖包
  • go build 最终交付时生成可执行文件
  • go run 可以直接运行 Go 源码文件,开发调试阶段使用

hello world

1
2
3
4
$mkdir ~/goprojects // 创建一个可以集合所有专栏项目的根文件夹
$cd ~/goprojects
$mkdir helloworld // 创建存储helloworld示例的文件夹
$cd helloworld

如果要在源文件的名字中使用多个单词,我们通常直接是将多个单词连接起来作为源文件名,而不是使用其他分隔符,比如下划线。也就是说,我们通常使用 helloworld.go 作为文件名而不是 hello_world.go。这是因为下划线这种分隔符,在 Go 源文件命名中有特殊作用,这个我们会在以后的讲解中详细说明。总的来说,我们尽量不要用两个以上的单词组合作为文件名,否则就很难分辨了

main.go

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
    fmt.Println("hello, world")
}
1
2
3
$go build main.go
$./main
hello, world

作为 Go 开发人员,请在提交你的代码前使用 Gofmt 格式化你的 Go 源码

  • import “fmt” 一行中“fmt”代表的是包的导入路径(Import),它表示的是标准库下的 fmt 目录,整个 import 声明语句的含义是导入标准库 fmt 目录下的包;
  • fmt.Println 函数调用一行中的“fmt”代表的则是包名。
  • 在 Go 语言中,只有首字母为大写的标识符才是导出的(Exported),才能对包外的代码可见;如果首字母是小写的,那么就说明这个标识符仅限于在声明它的包内可见。

编译

  • build 命令:最终交付时生成可执行文件
  • run 命令可以直接运行 Go 源码文件:开发调试阶段
1
2
3
4
5
6
7
8
$go build main.go
$./main
$hello, world



$go run main.go
$hello, world

复杂项目下 Go 程序的编译是怎样的

1
2
3
$cd ~/goprojects
$mkdir hellomodule
$cd hellomodule

main.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
  "github.com/valyala/fasthttp"
  "go.uber.org/zap"
)

var logger *zap.Logger

func init() {
  logger, _ = zap.NewProduction()
}

func fastHTTPHandler(ctx *fasthttp.RequestCtx) {
  logger.Info("hello, go module", zap.ByteString("uri", ctx.RequestURI()))
}

func main() {
  fasthttp.ListenAndServe(":8081", fastHTTPHandler)
}

Go module

  • 在 Go 1.16 版本中,Go module 已经成为了 Go 默认的包依赖管理机制和 Go 源码构建机制
  • Go Module 的核心是一个名为 go.mod 的文件,在这个文件中存储了这个 module 对第三方依赖的全部信息
1
2
3
4
$go mod init github.com/bigwhite/hellomodule
go: creating new go.mod: module github.com/bigwhite/hellomodule
go: to add module requirements and sums:
  go mod tidy
  • 一个 module 就是一个包的集合,这些包和 module 一起打版本、发布和分发。go.mod 所在的目录被我们称为它声明的 module 的根目录
  • module 隐含了一个命名空间的概念,module 下每个包的导入路径都是由 module path 和包所在子目录的名字结合在一起构成
1
2
3
4
5
$go build main.go
main.go:4:2: no required module provides package github.com/valyala/fasthttp; to add it:
  go get github.com/valyala/fasthttp
main.go:5:2: no required module provides package go.uber.org/zap; to add it:
  go get go.uber.org/zap

go mod tidy 命令,让 Go 工具自动添加依赖包

1
2
3
4
5
$go mod tidy       
go: downloading go.uber.org/zap v1.18.1
go: downloading github.com/valyala/fasthttp v1.28.0
go: downloading github.com/andybalholm/brotli v1.0.2
... ...

go.sum 文件

  • Copilot 自动提示:用于描述依赖包的哈希值,这个文件会被每次构建时都会更新,这样就可以在构建时避免依赖包的更新
  • 记录了 hellomodule 的直接依赖和间接依赖包的相关版本的 hash 值,用来校验本地包的真实性。在构建的时候,如果本地依赖包的 hash 值与 go.sum 文件中记录的不一致,就会被拒绝构建

额外

可以通过 go env -w GO111MODULE=xxx 来设置。 默认有三个值:auto/off/on go env |grep GO111MODULE

报错package xxx is not in GOROOT or GOPATH 或者 cannot find package “xxx“ in any of

code runner VsCode 插件 VSCode + golang on Mac

comments powered by Disqus