- Go的优点
- 高效垃圾回收机制
- 类型安全和内存安全(没有隐式转换,只能显示转换)
- 快速编译(未使用包检测)
- 轻松实现高并发
- 支持utf-8(源码文件格式为utf-8,type 哈哈 int)
- 多核计算机(允许调用cpu核心数)
-
GOPATH 工作目录
bin pkg src 可执行文件 包文件 .a 源代码 GOROOT Go语言的安装目录
-
基本命令
- go get 获取远程包(需提前安装git)
- go run 运行
- go build 测试编译(package main 的文件)
- go fmt 格式化代码
- go install 编译包文件和整个程序
- go test 运行测试文件(**_test.go是测试文件,命名自己文件的时候需要注意)
- go doc 查看文档(本地官网 go -http=:8080 & 后台执行)
-
Go可见性规则
- 首字母大小写决 常量,变量,类型,接口,结构 是否可以被外部调用
- 函数名首字母小写=private
- 函数名首字母大写=public
-
Go类型和0值
- 字符型 byte
- bool 必须true、false。数字不行
- 引用类型:slice,map,chan
- func,可以赋值给变量
- Go中指针没有->操作,只有.操作和&取地址,空指针为nil,不是null/NULL
-
Go类型转换
- 没有隐式转换,只能显示转换
- 转换只能发生在两种相互兼容的类型之间(int<->float)
-
常量和常量枚举
- iota是常量计数器,从0起,组中每定义一个常量自动递增1
- 通过初始化规则和iota可以达到枚举效果
- 每遇到一个const关键字,iota就重置为0
const( a='A' b c=iota d ) output a,b,c,d: 65 65 2 3
-
Go控制语句
- 加加/减减只能是语句,不能是表达式(a--正确,b=a--错误)
- if/switch 前面可以跟一个初始化表达式,分号隔开
- switch 不用break,匹配自动停,如果匹配还想继续,要fallthrough
- goto; break; continue 可以配合标签名使用,跳转到标签处
-
Go数组
- 数组长度也算是类型
- 数组用new初始化,返回指针
p := new([10]int)//p是指向数组的指针
- 数组是值类型,传递的时候是拷贝的而不是传地址的
- 数组之间可以==或者!=(不同类型的数组不可以做任何直接比较)
a := [...]int{1, 2, 3} a :=[2]int 中括号里面必须有东西才是数组,否则是切片 切片中括号里面一定没有东西
-
Go切片
- 本身不是数组,指向底层数组,可以关联底层数组的局部或全部,用make初始化,new初始化不能用
s1 := []int{tt: 1} s1 := make([]int, tt) 如果tt是const 都正确,不是则第一个错误
- copy函数 copy(s1,s2)
- append函数
s1 := make([]int,3,7) 则有 len(s1) = 3 cap(s1) = 7 append(s1,1,2,3,6,7,8,9,0,0,1) 此时s1长度越界,内存地址改变
-
Go语言map
- 三种定义方式
var m map[int]string m = map[int]string{} m := make(map[int]string,cap) //cap为指定容量,超出自动扩容 m := map[int]string{1:"a",2:"b",3:"c"}
delete 删除键值对
使用for range 对map和slice进行迭代操作
多层map使用
var m map[int]map[int]string m = make(map[int]map[int]string) //m[1] = make(map[int]string) //m[1][1]="OK" a, ok := m[1][1] if !ok { m[1] = make(map[int]string) } m[1][1] = "GOOD" //right
-
Go语言函数
- 函数不支持嵌套/重载和默认参数
- 无需声明原型
- 不定长度变参
func A(b string, a ...int){ //a必须是最后一个参数, a为一个切片 }
- 多返回值/命名返回值参数
- 匿名函数
func main(){ a := func(){ //匿名函数 fmt.Printfln("func A") } }
- 闭包
func main(){ f := closure(10) fmt.Printfln(f(1)) // 11 fmt.Printfln(f(2)) // 12 } func closure(x int) func(int) int { return func(y int ) int { return x + y } }
- 函数也可以作为一种类型使用
func main(){ a := A a() } func A(){ fmt.Printfln("func A") }
-
defer
- 执行方式类似于其他语言的析构函数,在函数体执行结束后按照调用顺序的相反顺序逐个执行(栈)
- 即使函数发生严重错误也会执行
- 支持匿名函数的调用
- 常用于资源清理/文件关闭/解锁以及记录时间等操作
- 通过与匿名函数配合可在return之后修改函数计算结果
- 如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已获得了拷贝,否则则是引用某个变量的地址
func main(){ for i := 0; i < 3; i++ { defer func() { fmt.Println(i) }() } } 输出: 3 3 3
- Go没有异常机制,使用panic/recover模式来处理错误
- panic可以在任何地方引发,但recover只有在defer调用的函数中有效
func main() { A() B() C() } func A() { fmt.Println("func A") } func B() { defer func() { //recover只有在defer调用的函数中有效 if err := recover(); err != nil { //panic阻断了运行,执行下面的回府 fmt.Println("Recover in B") } }() panic("Panic in B") //到这儿挂了 } func C() { fmt.Println("func C") } 输出: func A Recover in B func C
-
Go结构struct
- 嵌套结构,类似于继承
type human struct { sex int } type teacher struct { human age int city string } func main() { a := teacher{} a.sex = 5 a.city = "enshi" //a := teacher{human: human{sex: 1}} fmt.Println(a) }
- 匿名结构
a := &struct { Name string Age int }{ Name: "Joe", Age : 19, } fmt.Println(a)
- method
func(a *A)print(){} 调用的时候 a.print A类型的a是接收者
-
Go接口interface
- 接口是一个或多个方法签名的集合
- 只有声明,没有实现,没有数据字段
- 接口可以匿名嵌入到其他接口,或嵌入到结构中
- 实现接口:structural typing,只要实现某类型拥有该接口所有方法的签名,就算是实现接口
- 通过接口实现类似继承的功能,可以实现类似多态
- go中所有类型都实现了空接口,空接口可以作为任何类型数据的容器
- 接口转换,大接口转小接口可以,嵌套进去的小接口转不了大接口
- 对象赋值给接口时发生拷贝, 所以不能通过修改对象改变接口内容
- 只有当接口存储的类型和对象都是nil的时候, 接口才是nil,如果接口里存的是指向nil的指针,也不行
- 接口调用不会做receiver的自动转换
- 类型断言 ok pattern/ type switch 类型判断,接口转换
-
Go反射reflection
- 反射可大大提高程序的灵活性,是的interface{}有更大的发挥余地
- 反射使用TypeOf和ValueOf函数从接口中获取目标对象信息
- 反射会将匿名字段作为独立字段(匿名字段本质)
- 想要利用反射修改对象状态,前提是interface.data是settable,即pointer-interface
- 通过反射可以“动态”调用方法
-
Go并发
每个实例4-5k,轻便
并发不是并行:并发是由切换时间来实现“同时”运行,并行是多核多线程
goroutine 通过通信来共享内存,而不是共享内存来通信
func main() { wg := sync.WaitGroup{} for i := 0; i < 10; i++ { wg.Add(1) go Go(&wg, i) } wg.Wait() } func Go(wg *sync.WaitGroup, ind int) { a := 1 for i := 0; i < 10000; i++ { a += i } fmt.Println(ind, a) wg.Add(-1) //wg.Done() }
- Channel
- Channel是goroutine沟通的桥梁,大都是阻塞同步的
- 有缓存的是异步的,无缓存的是同步阻塞
- 通过make创建,close关闭
- Channel是引用类型
- 可以使用for range 来迭代不断操作channel
func main() { c := make(chan bool, 10) for i := 0; i < 10; i++ { go Go(c, i) } for i := 0; i < 10; i++ { <-c } } func Go(c chan bool, ind int) { a := 1 for i := 0; i < 10000; i++ { a += i } fmt.Println(ind, a) c <- true }
- 可以设置单向或双向通道
- 可以设置缓存大小,在未被填满前不会发生阻塞
- Channel是goroutine沟通的桥梁,大都是阻塞同步的
- Select
- 可处理一个或多个channel的发送与接收(类似于switch)
- 同时有多个可用的channel时按照随机顺序处理
- 可用空的select来阻塞main函数
func main(){ select{} //死循环 }
- 可设置超时
func main(){ c := make(chan int) select{ case v := <- c: fmt.Println(v) case <- time.After(3*time.Second): //返回的是一个chan fmt.Println("Timeout!") } }