[TOC]
[https://github.com/golang](https://github.com/golang)
手册
[https://cloud.tencent.com/developer/section/1142075](https://cloud.tencent.com/developer/section/1142075)
下载地址
[http://mirrors.ustc.edu.cn/golang/](http://mirrors.ustc.edu.cn/golang/)
# 优势
* 可以直接编译成机器码,不依赖其他库,glibc的版本有一定要求,部署就是扔一个文件上去
* 跨平台编译,如果你写的代码不包含cgo,那么就可以做到windows系统编译linux的应用.go引用了plan9的代码,这就是不依赖系统的信息
* 内嵌c支持,Go里面也可以直接包含c代码,利用现有的丰富c库
自动搜索所有函数并集中到一个.a文件
生成library时候是会自动把`$GOPATH/src/github.com/cyent/golang/example/stringutil/`下面所有.go文件里包含的函数集中到`stringutil.a`中(根据这些.go文件中的package xxx来自动加入到一个.a),因此如果存在相同的函数,会报错提示重复
# 学习资料
go语言官网: https://golang.org/
go中文社区: https://studygolang.com/
go中文在线文档: https://studygolang.com/pkgdoc
# 命令源码文件
如果一个源码文件声明属于main包,并且包含一个无参数声明且无结果声明的main函数,那么它就是命令源码文件
~~~
package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
~~~
# 命令行
* 编译go代码,生成一个可执行程序
~~~
go build xxx.go
~~~
然后这个程序就可以执行了
* 不生成可执行文件,直接运行
~~~
go run xxx.go
~~~
* `go install`
配置GOPATH到src同级的绝对目录`src/xx`
需要配置GOBIN
到src目录执行go install就行,会生成2个目录在src同级
自动生成pkg和bin
pkg放平台,bin放可执行程序
# 环境变量
* `src`存放源代码(比如:.go .c .h .s等) 按照golang默认约定,go run,go install等命令的当前工作路径(即在此路径下执行上述命令)。
* `pkg`编译时生成的中间文件(比如:.a) golang编译包时
* `bin`编译后生成的可执行文件(为了方便,可以把此目录加入到 $PATH 变量中,如果有多个gopath,那么使用`${GOPATH//://bin:}/bin`添加所有的bin目录)
代码目录结构: GOPATH下的src目录就是接下来开发程序的主要目录,所有的源码都是放在这个目录下面,那么一般我们的做法就是一个目录一个项目,
例如: $GOPATH/src/mymath 表示mymath这个应用包或者可执行应用,这个根据package是main还是其他来决定,main的话就是可执行应用,其他的话就是应用包,这个会在后续详细介绍package
`go install/go get`和 go的工具等会用到GOPATH环境变量
goroot在上面
~~~
export GOPATH=/Users/hopkings/www/Go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN
~~~
**go get**
会做两件事:
1. 从远程下载需要用到的包
2. 执行go install
`go get = git clone + go install` 从指定源上面下载或者更新指定的代码和依赖,并对他们进行编译和安装
**go install**
go install 会生成可执行文件直接放到bin目录下,当然这是有前提的
你编译的是可执行文件,如果是一个普通的包,会被编译生成到pkg目录下该文件是.a结尾
# go build
1. 运行go build命令时加入标记-x,这样可以看到go build命令具体都执行了哪些操作。另外也可以加入-n,只查看具体操作不执行他们
2. 运行go build命令加入标记-v,这样可以看到go build命令编译源码包的名称,和-a标记搭配很有用
3. 执行该命令而且不加参数,会试图把当前目录作为代码包编译. `-a`所有涉及到代码包都被编译,不加只会编译归档文件而不是最新的代码包
# go get
从github下载后安装到GOPATH第一个工作区的相应目录中.如果存在GOBIN,那么仅包含命令元am文件代码会装到GOBIN那
-u: 下载并安装代码包,不论是否存在
-d: 只下载不安装
-fix: 下载代码包后先运行一个用于根据当前go版本修正代码的工具,然后再安装代码包
-t: **同时下载测试所需的代码包**
-insecure: 允许通过非安全的网络协议下载,比如http
**uses insecure protocol**
~~~
export url=''
export project=''
git config --global url."git@${url}:".insteadOf "http://${url}/" go get -v -insecure "${url}${project}"
~~~
# go env
![](https://box.kancloud.cn/305b2452adbacf4e2dfdaa6087f4990f_804x728.png)
# 查看编译的依赖
mac上没有ldd和strace
mac对应的是otool和strace,需要root
查看动态链接库`otool -L`
~~~
ldd 可执行文件
~~~
![](https://box.kancloud.cn/722e10006afbec8b3bad4a20439aa565_1350x582.png)
上图中的三列数据分别代表:
1. 第一列:程序依赖的库
2. 第二列:系统提供的对应库
3. 第三列:库加载的开始地址
通过对比第一列和第二列数据,可以分析程序依赖的库和系统实际提供的库,看两者是否相匹配。
通过第三列数据,可以知道在当前的库中的符号在对应的进程的地址空间中的开始位置
# 交叉编译
![](https://box.kancloud.cn/284d319c47a6d8154bdf737056ae901c_1268x404.png)
有效的`$GOOS`和`$GOARCH`组合如下
~~~
$GOOS $GOARCH
android arm
darwin 386
darwin amd64
darwin arm
darwin arm64
dragonfly amd64
freebsd 386
freebsd amd64
freebsd arm
linux 386
linux amd64
linux arm
linux arm64
linux ppc64
linux ppc64le
linux mips
linux mipsle
linux mips64
linux mips64le
netbsd 386
netbsd amd64
netbsd arm
openbsd 386
openbsd amd64
openbsd arm
plan9 386
plan9 amd64
solaris amd64
windows 386
windows amd64
~~~
交叉编译主要是两个编译环境参数 `$GOOS` 和 `$GOARCH` 的设定
`$GOOS`代表编译的目标系统,`$GOARCH`代表编译的处理器体系结构
`$GOOS`可选值如下
~~~
darwin
dragonfly
freebsd
linux
netbsd
openbsd
plan9
solaris
windows
~~~
`$GOARCH`可选值如下
~~~
386
amd64
arm
~~~
Mac 下编译 Linux 和 Windows 64位可执行程序
~~~
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
~~~
在Linux系统下跨平台编译
~~~shell
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build xxx.go
~~~
在Windows系统下跨平台编译
~~~shell
set CGO_ENABLED=0
set GOARCH=386
set GOOS=windows
go build xxx.go
~~~
选择性编译
虽然golang 可以跨平台编译,但却无法解决系统的差异性。总在一些时候我们会直接调用操作系统函数。相同功能编写类似xxx_windows.go xxx.Linux.go文件,根据操作系统编译对应源文件。而不是在文件中用if else规划执行路径。 要实现选择性编译需要在文件顶部增加构建标记。
~~~
// +build
~~~
此标记必须出现在文件顶部,仅由空行或其他注释行开头。也就是必须在Package 语句前。此标记后接约束参数,格式为 // +build A,B !C,D 逗号为且,空格为或,!为非。代表编译此文件需符合 (A且B) 或 ((非C)且D) 。A和C的可选参数可参见本文上面的 $GOOS参数,B和D的可选参数可参见$GOARCH 。比如
~~~
// +build !windows,386
//此文件在非windows操作系统 且386处理器时编译
~~~
最后, Golang为跨系统运行的确是已经做得够好了。没有C C++的历史包袱,但充分吸取了他们的诸多特点,为加快工作效率损失的软件性能是值得的
# 编译器
在网络上的诸多教程中可能会看到下面的编译命令
~~~
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build hello.go
~~~
其中CGO\_ENABLED=0的意思是使用C语言版本的GO编译器,参数配置为0的时候就关闭C语言版本的编译器了。自从golang1.5以后go就使用go语言编译器进行编译了。在golang1.9当中没有使用CGO\_ENABLED参数发现依然可以正常编译。当然使用了也可以正常编译。比如把CGO\_ENABLED参数设置成1,即在编译的过程当中使用CGO编译器,我发现依然是可以正常编译的。
实际上如果在go当中使用了C的库,比如`import "C"`默认使用go build的时候就会启动CGO编译器,当然我们可以使用CGO\_ENABLED=0来控制go build是否使用CGO编译器。
# GOPROXY
~~~
export GOPROXY=https://goproxy.io
~~~
or
~~~
$env:GOPROXY = "https://goproxy.io"
~~~
![](https://box.kancloud.cn/ee6a7034d5a6cc9d1e0d3023b0d50987_964x474.png)
# 压缩可执行文件
首先加上编译参数`-ldflags`
`-s`相当于strip掉符号表, 但是以后就没办法在gdb里查看行号和文件了。 `-w` 告知连接器放弃所有debug信息
~~~
$ go build -ldflags '-w -s'
~~~
使用upx压缩,Linux、Mac和Win都有,这里以Mac为例
upx就是对可执行文件进行压缩,然后可以已极快的速度解压并运行
~~~
$ brew install upx
$ upx etcd-cli
~~~
Golang开发的程序都会比较大,这是因为Golang是静态编译的,编译打包之后基本就不会再对其他类库有依赖了,所以会比较大。举个例子:C++程序可以调用dll,所以打包的时候可以不把dll打进去,包自然就小了。之前还有看到过有人使用`GO -> C -- dll --> C -> GO`的方式间接实现了Golang的伪动态链接
# go cache
通过运行`go env GOCACHE`命令来查看缓存目录的路径。缓存的数据总是能够正确地反映出当时的各种源码文件、构建环境、编译器选项等等的真实情况。
一旦有任何变动,缓存数据就会失效,go 命令就会再次真正地执行操作。所以我们并不用担心打印出的缓存数据不是实时的结果。go 命令会定期地删除最近未使用的缓存数据,但是,如果你想手动删除所有的缓存数据,运行一下`go clean -cache`命令就好了
# goland调试
菜单依次选择“Run”->“Edit configurations”如下图所示:
![](https://box.kancloud.cn/ad7b0561ffefc65d8219dc39324116e7_431x329.png)
![](https://box.kancloud.cn/47da02127e84f69d4eabf1ee1117482e_1098x583.png)
- 基础
- 简介
- 主要特征
- 变量和常量
- 编码转换
- 数组
- byte与rune
- big
- sort接口
- 和mysql类型对应
- 函数
- 闭包
- 工作区
- 复合类型
- 指针
- 切片
- map
- 结构体
- sync.Map
- 随机数
- 面向对象
- 匿名组合
- 方法
- 接口
- 权限
- 类型查询
- 异常处理
- error
- panic
- recover
- 自定义错误
- 字符串处理
- 正则表达式
- json
- 文件操作
- os
- 文件读写
- 目录
- bufio
- ioutil
- gob
- 栈帧的内存布局
- shell
- 时间处理
- time详情
- time使用
- new和make的区别
- container
- list
- heap
- ring
- 测试
- 单元测试
- Mock依赖
- delve
- 命令
- TestMain
- path和filepath包
- log日志
- 反射
- 详解
- plugin包
- 信号
- goto
- 协程
- 简介
- 创建
- 协程退出
- runtime
- channel
- select
- 死锁
- 互斥锁
- 读写锁
- 条件变量
- 嵌套
- 计算单个协程占用内存
- 执行规则
- 原子操作
- WaitGroup
- 定时器
- 对象池
- sync.once
- 网络编程
- 分层模型
- socket
- tcp
- udp
- 服务端
- 客户端
- 并发服务器
- Http
- 简介
- http服务器
- http客户端
- 爬虫
- 平滑重启
- context
- httptest
- 优雅中止
- web服务平滑重启
- beego
- 安装
- 路由器
- orm
- 单表增删改查
- 多级表
- orm使用
- 高级查询
- 关系查询
- SQL查询
- 元数据二次定义
- 控制器
- 参数解析
- 过滤器
- 数据输出
- 表单数据验证
- 错误处理
- 日志
- 模块
- cache
- task
- 调试模块
- config
- 部署
- 一些包
- gjson
- goredis
- collection
- sjson
- redigo
- aliyunoss
- 密码
- 对称加密
- 非对称加密
- 单向散列函数
- 消息认证
- 数字签名
- mysql优化
- 常见错误
- go run的错误
- 新手常见错误
- 中级错误
- 高级错误
- 常用工具
- 协程-泄露
- go env
- gometalinter代码检查
- go build
- go clean
- go test
- 包管理器
- go mod
- gopm
- go fmt
- pprof
- 提高编译
- go get
- 代理
- 其他的知识
- go内存对齐
- 细节总结
- nginx路由匹配
- 一些博客
- redis为什么快
- cpu高速缓存
- 常用命令
- Go 永久阻塞的方法
- 常用技巧
- 密码加密解密
- for 循环迭代变量
- 备注
- 垃圾回收
- 协程和纤程
- tar-gz
- 红包算法
- 解决golang.org/x 下载失败
- 逃逸分析
- docker
- 镜像
- 容器
- 数据卷
- 网络管理
- 网络模式
- dockerfile
- docker-composer
- 微服务
- protoBuf
- GRPC
- tls
- consul
- micro
- crontab
- shell调用
- gorhill/cronexpr
- raft
- go操作etcd
- mongodb