Go 语言新手笔记(一)
Go 语言 2009 年面世,几个成功项目 Docker, Kubernetes, etcs, consul, flannel, 还有 Terraform。Go 编译运行快,听说学习也不难。安装好 Go 后,有两个环境变量很重要, GOPATH 是工作目录,GOROOT 是 Go 的安装目录, 如 /usr/local/go。GOPATH 允许多个目录,用 : 或 ;(Windows 下) 分隔,当 GOPATH 有多个目录,go get 命令的包放在第一个目录下。
$GOPATH 目录中约定的三个子目录
Go 还有复数类型, complex64(实虚两部分为 float32), compex128,
Go 的类型定义可以在 $GOROOT/src/builtlin/builtin.go 中看到,如
一些 Go 变量声明与赋值的代码
_ 还有许多避免编译不过的妙用,如 import _"fmt", var _=log.Println 等
Go 语言的数据是值类型,向函数传递数组会产生一份副本,而更新数组数据时,考虑用数组指针。数组的声明是
与通常的语言 string[] 反过来了,中括号提前
Go 的字符串初始为空字符串,var s string 相当于 s := ""
Go 用 const 声明常量,iota 是每次出现加 1 的常量,从 0 开始,const 声明中未赋值的常量将继承上一个的值
iota 在每遇到一个新的常量块时又会重置为 0
Go 净整一些奇怪的单词,像前面的 rune(符文,文字), iota(希腊字母第九个字母:Ι,ι, 微小,一点的意思)
Go 的反引号像是 Python raw 字符串的效果,
Go 运算符很丰富,其他语言中的逻辑,位运算, ++, --,运算后赋值(如 +=, %=, <<=, >>=, &= 等) 都有。还有像 C/C++ 的 & 和 *, 如 &a : 取 a 变量的地址,和 *a: 指针变量。
还有几个特殊的运算符,位清零 &^, x &^ y x 上对应 y 位置上是 1 时取零。^ 一元操作时按位取反,二元操作为异或
字符串也是一个字符数组,如 len("abc"), "abc"[1]。拼接字符串,用加号 "aa" + "bb", mt.Sprintf(), strings.Joint([]string{"aa", "bb"}, ",") 或用 bytes.Buffer 来 WriteString("aa"), 或 string.Builder
字符串的处理包 bytes, strings, strconv 和 uncicode。
Go 的 switch...case 语句本身是默认每个 case 后都是 break 了的,除非加个 fallthrough 又能回到 Java 的 switch...case 的入口效果。Go 的 switch...case 也可以是个表达式,有返回值的。switch...case 的 default 可以写在任何位置。switch...case 也可没有表达式,就相当于一个 if/else 语句了, 还可以带个初始化语句,以下三种形式
Go 针对异步通道操作有专门的 select 语句,select 会监听分支语句中的通道直到变为非阻塞状态,有多个分支可运行,随机选一个;没可运行分,且有 default 就执行 default; 既没可运行也没 default, 继续阻塞,直到出现可运行分支。
for 语句的格式是
for-range 循环是 Go 特别的,可以迭代集合,能在迭代的时候获得索引和值,或 key(对于 map), 如
Go 的 if...else 的条件是不需要用括号的, if 布尔表达式 {} else if 布尔表达式 {} else {}, 表达式中还能用 ; 连接多个,最后的返回值为布尔值,如 if x:=f(); x<y {}
Go 的 break 还能跳到标签位置, 这有助于跳出多重循环。Go 也有 continue, goto, 同样不建议用 goto 语句。continue 和 goto 都能跳到标签位置。
可见性规则,标识符以大写字母开头的才能导出被外部包代码所用,所以工具方法名首字母都是大写。命令规范是公有函数用 Pascal 命名法(首字母大写的即大驼峰),私有函数用小驼峰式命名法。
Go 语句后的分号通常省略。左花括号不能独点一行,否则不能编译。Go 的注释方法与 Java 是一样的,// 或 /* */
Go 组织代码也用包,但不必像 Java 那样严格的与目录名对应。Go 的每个 .go 文件都必须属于某个用,用 package 声明,同一目录下的多个 .go 文件只能属于同一个包,同一包中的 .go 文件定义的全局变量和公有函数名(首字母大写的)不能冲突。
Go 程序入口必须是 main 包,并且还要 main() 入口函数。每个包可有 init() 函数,init() 函数的签名与 main() 一样,无参数无返回值,如
在包被导入式首先被执行,一个包可有多个 init() 函数,如
居然是合法的,两个 init() 函数在导入式都会被执行,顺序不是确定的
Go 导入(import) 包是使用目录名作为包的路径而非 package 声明的包名,实际应用中还是应像 Java 那样尽量保持包名与目录包一致。import "match/big" 会导入 $GOROOT 目录下的 src/match/big 目录,使用 big.Int 时的 big 才是 .go 文件中定义的包名
几种特殊的 import 方式
Go 语言的标准库在 $GOROOT/src 中,如 Mac OS X 下的
如果想安装 GitHub 上的项目到本地,可执行
如果有指定了 GOPATH 环境变量, go get 下载和编译生成的就会放到 $GOPATH 对应的 src, pkg, 和 bin 目录中
Go 的包依赖管理工具有 glide, godep, govendor, GoModules。
go install github.com/gocolly/colly@latest 和 go get .... 差不多的功能, 区别好像是 go install 不克隆源代码,还有一个 go build
Go 项目的基本结构是 $GOPATH/{src,pkg,bin}, 有 main.main 函数可用
godoc 命令已经从 go 1.1.13 中移除,要安装它的话可用命令
Go 编译构建相关的命令有 go run, go build, 和 go install. 如果发布的编译文件不希望别人看到源代码,用下面的参数构建
使用 go mod 系列命令
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
$GOPATH 目录中约定的三个子目录
- src: 存放 .go, .c, .h, .s 等源码文件,go run, go install 等命令也要在该目录下执行
- pkg: 存放编译时生成的中间文件,如 .a
- bin: 存放编译后的可执行文件
1var c rune = 'a'
2// 相当于 Java 的 int c = 'a'
3// 打印出来都是 97var c complex128=1.0+10iGo 的类型定义可以在 $GOROOT/src/builtlin/builtin.go 中看到,如
1type byte = unit8
2type rune = int32
3
4const (
5 true = 0 == 0
6 false = 0 != 0
7) 1package main
2
3import "fmt"
4
5func main() {
6 var (
7 a int
8 b bool
9 )
10 fmt.Println(a, b) // 0 false, Go 的类型也有像 Java 一样的零值,如 0, 空字符串, nil
11 a, b = 3, true
12 fmt.Println(a, b) // 3 true
13
14 c, d := 'k', 2.1 // 这种简单声明变量 a := 1 的方式只能在函数中
15 fmt.Println(c, d) // 107 2.1
16
17 e, f := 4, 5
18 e, f = f, e
19 fmt.Println(e, f) // 5 4
20
21 _, e = 7, 8 // _ 表示丢弃值,比如函数返回多值时
22 fmt.Println(e, f) // 8 4
23
24 var x = 9
25 fmt.Println(x) // 9
26}Go 语言的数据是值类型,向函数传递数组会产生一份副本,而更新数组数据时,考虑用数组指针。数组的声明是
1var arr = []string{"aa", "bb"}Go 的字符串初始为空字符串,var s string 相当于 s := ""
Go 用 const 声明常量,iota 是每次出现加 1 的常量,从 0 开始,const 声明中未赋值的常量将继承上一个的值
1func main() {
2 const (
3 a = iota
4 b = iota
5 c
6 d = 8
7 e
8 )
9
10 fmt.Print(a, b, c, d, e) // 0 1 2 88
11}Go 净整一些奇怪的单词,像前面的 rune(符文,文字), iota(希腊字母第九个字母:Ι,ι, 微小,一点的意思)
Go 的反引号像是 Python raw 字符串的效果,
fmt.Print(`a\nb`) 输出为 a\nb, \n 不被输出为行,像 Python 的 print(r"a\nb") 一样。Go 运算符很丰富,其他语言中的逻辑,位运算, ++, --,运算后赋值(如 +=, %=, <<=, >>=, &= 等) 都有。还有像 C/C++ 的 & 和 *, 如 &a : 取 a 变量的地址,和 *a: 指针变量。
还有几个特殊的运算符,位清零 &^, x &^ y x 上对应 y 位置上是 1 时取零。^ 一元操作时按位取反,二元操作为异或
字符串也是一个字符数组,如 len("abc"), "abc"[1]。拼接字符串,用加号 "aa" + "bb", mt.Sprintf(), strings.Joint([]string{"aa", "bb"}, ",") 或用 bytes.Buffer 来 WriteString("aa"), 或 string.Builder
字符串的处理包 bytes, strings, strconv 和 uncicode。
Go 的 switch...case 语句本身是默认每个 case 后都是 break 了的,除非加个 fallthrough 又能回到 Java 的 switch...case 的入口效果。Go 的 switch...case 也可以是个表达式,有返回值的。switch...case 的 default 可以写在任何位置。switch...case 也可没有表达式,就相当于一个 if/else 语句了, 还可以带个初始化语句,以下三种形式
1switch bb {
2case true: f1()
3fallthrough
4case false: f2()
5}
6
7switch {
8case x < y, x < t: f1()
9case x < z: f2()
10default: f3()
11}
12
13switch x:= f(); { // x:=f(); 为初始化语句
14case x<0: return -x
15default: return x
16}
17
18switch t:=t.(type) { // 比较类型
19case bool: f1()
20case int: f2()
21case *int: f3()
22}for 语句的格式是
for 初始化语句; 条件语句; 修饰语句 {}, 每部分都可省略,如果全省略就是 for ;;{}, 就是 for {} 了,变成无限循环了。for-range 循环是 Go 特别的,可以迭代集合,能在迭代的时候获得索引和值,或 key(对于 map), 如
1for idx, val := range coll {}<br />
2for key := range amap {}Go 的 break 还能跳到标签位置, 这有助于跳出多重循环。Go 也有 continue, goto, 同样不建议用 goto 语句。continue 和 goto 都能跳到标签位置。
可见性规则,标识符以大写字母开头的才能导出被外部包代码所用,所以工具方法名首字母都是大写。命令规范是公有函数用 Pascal 命名法(首字母大写的即大驼峰),私有函数用小驼峰式命名法。
Go 语句后的分号通常省略。左花括号不能独点一行,否则不能编译。Go 的注释方法与 Java 是一样的,// 或 /* */
Go 组织代码也用包,但不必像 Java 那样严格的与目录名对应。Go 的每个 .go 文件都必须属于某个用,用 package 声明,同一目录下的多个 .go 文件只能属于同一个包,同一包中的 .go 文件定义的全局变量和公有函数名(首字母大写的)不能冲突。
Go 程序入口必须是 main 包,并且还要 main() 入口函数。每个包可有 init() 函数,init() 函数的签名与 main() 一样,无参数无返回值,如
1func init() {
2 fmt.Println("init main package")
3} 1package main
2
3import "fmt"
4
5func init() {
6 fmt.Println("1 init main package")
7}
8
9func init() {
10 fmt.Println("2 init main package")
11}
12
13func main() {
14 fmt.Println("hello world")
15}Go 导入(import) 包是使用目录名作为包的路径而非 package 声明的包名,实际应用中还是应像 Java 那样尽量保持包名与目录包一致。import "match/big" 会导入 $GOROOT 目录下的 src/match/big 目录,使用 big.Int 时的 big 才是 .go 文件中定义的包名
几种特殊的 import 方式
import ."fmt": 使用时可省略包名,如 Println(),而不用 fmt.Println(), 像 Java 的静态引入import f"fmt": 别名引入,f.Println()import _"fmt": _ 操作引入包只为了调用包的 init() 函数
Go 语言的标准库在 $GOROOT/src 中,如 Mac OS X 下的
/usr/local/Cellar/go/1.16.6/libexec/src如果想安装 GitHub 上的项目到本地,可执行
go get -u github.com/ffhelicopter/tmm然后在代码中就可以像下面那样导入了
import "github.com/ffhelicopter/tmm"go get 下载到的源文件会放到 ~/go/src 目录中,编译生成的 .a 二进制放到 ~/go/pkg 目录中,如果有 main, 生成的二进制执行文件放到 ~/go/src 目录中
如果有指定了 GOPATH 环境变量, go get 下载和编译生成的就会放到 $GOPATH 对应的 src, pkg, 和 bin 目录中
Go 的包依赖管理工具有 glide, godep, govendor, GoModules。
go install github.com/gocolly/colly@latest 和 go get .... 差不多的功能, 区别好像是 go install 不克隆源代码,还有一个 go build
Go 项目的基本结构是 $GOPATH/{src,pkg,bin}, 有 main.main 函数可用
go install src/test.go会成 $GOPATH/bin 目录中生成可执行的 test 文件
godoc 命令已经从 go 1.1.13 中移除,要安装它的话可用命令
go get golang.org/x/tools/cmd/godoc安装,然后运行
bin/godoc -http=localhost:6060启动 godoc web 服务,就能在浏览器中打开 http://localhost:6060
Go 编译构建相关的命令有 go run, go build, 和 go install. 如果发布的编译文件不希望别人看到源代码,用下面的参数构建
go build -ldflags "-w -s" src/test.goGo 自 1.11 新增了对模块的支持, 通过 GO111MODULE=auto|on|off 来控制关闭与开启,
go env 可查看所有 Go 环境变量。- GO111MODULE=off 时,从 $GOPATH 和 vender 目录中寻找包
- GO111MODULE=on 时,忽略 $GOPATh 和 vender 目录,根据 go.mod 下载依赖
- GO111MODULE=auto 时,判断是否有 $GOPATH/go.mod 文件来开启与否
go env -w GO111MODULE=auto 设置使用 go mod 系列命令
$ go env -w GO111MODULE=autoGo 模块的使用仍然像是 Java 的模块一样糊涂,先不管它了。 永久链接 https://yanbin.blog/go-language-notes-1/, 来自 隔叶黄莺 Yanbin's Blog
$ go mod init hello
$ unset GOPATH
$ go mod tidy
$ ...
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。