官网非常好的教程https://tour.go-zh.org
Go的50度灰:Golang新开发者要注意的陷阱和常见错误 https://colobu.com/2015/09/07/gotchas-and-common-mistakes-in-go-golang/#
别人写的非常好的笔记,强推astaxie/build-web-application-with-golang
别人写的笔记https://www.zybuluo.com/octopus/note/1212993
安装相关
墙
直接
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.io,direct
以下可以不用看了
必须要翻墙!!!!
挂github的代理,如果要用socks5的话,必须做个二级代理转成http的,可以使用cow
然后
git config --global http.proxy "http://127.0.0.1:7777"
export http_proxy="http://127.0.0.1:7777"
export https_proxy="http://127.0.0.1:7777"
export all_proxy="http://127.0.0.1:7777"
win 下的 cmd 需要把 export
换成 set
,powershell 需要换成 $Env:
IDE用vscode,装上go
的插件。
然后随便新建一个xxx.go
,然后会提示你装go
的一些包,此时直接按install all
。
若翻墙失效,在 vs 的终端里会告诉你哪些包失效。
复制这些失效的包地址(包括github和golang.org的包),然后手动用git bash
来装,具体来说就是
go get -u -v xxxxx
xxxxx
是上面得到的包地址。
其他
go
自带命令介绍可以看这
go build
、go test
执行本目录下所有目录(递归),参考golang-tests-in-sub-directory,即我们用./...
即可
笔记
这个语言有着一个特别奇葩的语言规范。。。。
- 包内函数名第一个字母是大写则为可见(public),否则为隐藏(private)。这一点特别奇葩
- 变量类型是放在变量名后面。。。。函数返回值也是放在函数名后面。。。
- _(下划线)是个特殊的变量名,任何赋予它的值都会被丢弃。
- 函数可以返回多个值demo
- 返回值可以命名,命名的返回值相当于在函数顶部定义了该变量demo
- 在函数中,简洁赋值语句 := 可在类型明确的地方代替 var 声明。
- 函数外的每个语句都必须以关键字开始(var, func 等等),因此 := 结构不能在函数外使用。
- 基本类型
- 错误类型是
error
,新建一个字符串提示的错误可以用errors.New("blabla")
- 字符串是不能更改的,不过可以这样
s := "hello"
c := []byte(s) // 将字符串 s 转换为 []byte 类型
c[0] = 'c'
s2 := string(c) // 再转换回 string 类型
iota
关键字可以用来替代enum
,const
里面每行就增1,其每遇到一个const
就会重置为0
const (
a = iota //a=0
b = "B"
c = iota //c=2
d, e, f = iota, iota, iota //d=3,e=3,f=3
g = iota //g = 4
)
- 无隐式转换
- 数值常量可以很大,其一开始是用高精度存储的,比如
const Big = 1 << 100
是合法的,用Big >> 80
相当于int(1 << 20)
- 结构体匿名字段,会像继承一样将元素组合进来,demo
- 获取类型:
a.(type)
,但只能用于switch
的语句里 - 类型断言:
value, ok := a.(int)
,若ok == true
表示a
的类型的确是int
,且值为value
。demo - 函数参数的开销(拷贝与指针)比较:文章。总之就是,大一点的结构体/基本数据结构就用指针吧。。。
- 没有
while
,用没有分号的for
来代替了关键字while
for
、if
、switch
可以不写圆括号,但大括号必须写if
可以在条件语句前加前置语句,在前置语句定义的变量作用域在if
内,且能被对应的else
使用demoswitch
同样可以加前置语句,不用加break
,case
的值可以不是常量!switch
也能没有条件语句!这样可以代替多个if-then-else
语句!demo- 比较奇葩的关键字
defer
,该语句调用的函数会在外函数执行完后才执行(但参数是立即计算)demo,这个关键字的好处在于可以避免一些bug的发生demo - 多条
defer
会以栈的方式(后进先出)来执行 - 没有指针运算
- 数组切片只是引用,不是复制了一份数据
- 数组有
len
和cap
的属性,最好看例子来理解demo1,demo2 - 切片详细请看文章
- 若想给某个类型加方法(
Type.Func
),Type
要么在同一包内定义,要么得type myType Type
,然后再写新方法myType.Func
demo - go里的指针似乎就是结合了c里的指针和引用?demo1,demo2
- 指针接受者能改变数据,值接受者不行。具体比较看demo
- 接口可以用c++的基类指针来理解
- 接口实现若为“值接受者”,“指针/值"都能使用;但若为“指针接受者”,则只有“指针才能使用”。demo
- 接口要注意一下
nil
demo - 给一个好玩的抽象类玩法
package main
import "fmt"
type A struct {
X string
}
func (a *A) G() *A {
return a;
}
func (a *A) fu() string {
return a.X
}
type B struct {
* A
}
type C interface {
G() *A
fu() string
}
func main() {
x := A{X: "hehe"}
y := B{A: &A{X: "hehe"}}
fmt.Println(x.fu())
fmt.Println(y.fu())
fmt.Println(x.X)
fmt.Println(y.X)
var z C
z = &x
fmt.Println(z.fu())
z = &y
fmt.Println(z.fu())
fmt.Println(z.G().X)
fmt.Println(z.G().fu())
}
package main
import "fmt"
type A struct {
X string
}
func (a *A) Set(x string) {
a.X = x
}
func (a *A) Get() string {
return a.X
}
type B interface {
Set(string)
Get() string
}
func main() {
a := &A{X: "hehe"}
var b, c B
b = a
c = b
fmt.Println(a.Get())
fmt.Println(b.Get())
fmt.Println(c.Get())
c.Set("gg")
fmt.Println(a.Get())
fmt.Println(b.Get())
fmt.Println(c.Get())
}
/*
hehe
hehe
hehe
gg
gg
gg
*/
go
后面跟的参数都会在当前协程算,调用的函数才是会新开一个协程执行chan int
是可读可写的int阻塞消息队列;chan <- int
是只写的;<- chan int
是只读的select
你可以认为是for + switch
的死循环context
的介绍1、介绍2go routine
常用例子
ch := make(chan Data, numberOfGoroutine)
wg := sync.WaitGroup{}
wg.Add(numberOfGoroutine)
for gid := 0; gid < numberOfGoroutine; gid++ {
go func() {
for {
data, ok := <- ch
if !ok {
wg.Done()
return
}
// Do something
}
}()
}
// send data to ch
close(ch)
wg.Wait()
测试
禁止 cache
$ go test -count=1
CI
.gitlab-ci.yml
:参见别人的文章.travis.yml
:
language: go
go:
- "1.6"
- "1.7"
- "1.8"
- "1.9"
- "1.10"
- "1.11"
- "1.12"
- "master"
script:
- cd example && go build ./...
交叉编译
可以看别人的文章
你大概可以写一个这样的脚本
#!/bin/bash
v="$1"
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o ./cf${v}_win-amd64/cf.exe ../cf.go
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -o ./cf${v}_darwin-amd64/cf ../cf.go
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o ./cf${v}_linux-amd64/cf ../cf.go
注释规范
包管理
Go是不自带包管理工具的。。也就是包的版本是无法写死的,这就会导致很不稳定的问题。不过Go官方出了一个拓展dep来解决这个问题。中文使用教程
一些好用的库
大全1 hackstoic/golang-open-source-projects
大全2 avelino/awesome-go
测试
- stretchr/testify
- qiuker521/httptest 这么好的东西居然没人发现
- mock http