go学习笔记
初始go
异常处理的defer是个不错的特性,虽然说有人反驳说其中的java代码不够合理,但是这种方式确实对c是一个巨大的进步。
工程编译根据方便,没有Makefile文件,只要一个go命令即可。但是必须要设置GOPATH路径,这一步能省掉就更好了。
顺序编程
变量:支持:int,字符串,数组,数组切片,结构体,指针,字典,函数指针。
iota:在每次const是初始化为0,每出现一次会自增1。
全局变量不支持类型推导——:=
go 的取反是^而不是~
float64相当于c中的double。
浮点数的比较不可以使用==,因为有精度问题。
字符串在go中是一种基本类型:
go中有两种字符类型:byte,其实就是uint8,代表utf-8的单个字节,另一个是rune,代表单个Unicode字符。
go的api多数假设字符串为utf-8编码。
go中的数组时值类型,作为函数参数是进行了一次的拷贝操作。函数无法修改入参的值。
var v [3][5]int = [3][5] int{{1,2},{3,4},{5,6}}//数组初始化
数组长度定义后无法修改,数组时值类型,每次传递产生一个副本。
数组切片:
切片可以动态扩展空间(是不是无限制扩展?),随意传递而不会重复复制。
s := v[:]
s := v[:5]
s := v[5:]
s := v[1:5]
s := make([]int, 5)//5个元素
s := make([]int, 5, 10)//5个元素,存储能力为10
s := []int{1,2,3,4,5,6}
使用cap可以获得切片的存储能力,len可以获得切片的长度。
基于数组创建切片存储能力就是数组的大小。
append函数可以为切片添加元素。
s = append(s, 1 , 2, 3, 4)//为s添加四个元素。第二个参数是可变参数。
vslice = append(vslice, vslice...)//为一个切片追加另外一个切片。省略号表示取切片的每个元素。
基于数组切片创建切片:范围可以超过原有的len,但是不可以超过cap。否则会异常。
newvs := vslice[:50]
fmt.Println( cap(newvs), len (newvs))
更改数组的切片的值,会更改数组。切片类似于数组指针。
!数组切片在append后,便是脱离了原有的数组,形成了一块新的存储,更改切片值,不会再更改原有的数组内容。这是一个容易引起错误的地方。
可以使用copy函数对切片进行复制:将一个切片的内容复制到另外一个切片中。copy从第二个参数中拷贝入第一个参数中。拷贝的个数时两个切片最小元素个数。不会将剩余元素设置为空。
MAP:
定义:
var mymap map[ int]string 变量名 key类型 value类型
var mymap map[ int]string = map[int]string{1: "1", 2:"2" , 3:"3"}//定义并初始化
复制类似Python。可以用make创建,并制定存储能力。
删除用delete。
流程控制:
if后没有(),可以加变量定义(if i := 5; i > 2 && i <= 7{)。else必须与上一个}在一行。
switch:
条件可以是字符串等,不限定为常量或整数。
没有break。不会自动执行下一个,需要手动添加fallthrough。没有条件是,逻辑相当于 if else if ...
循环:
无限循环的写法。
for {
}
循环条件中支持多重赋值。break可以控制停止那个循环。通过标签来实现,与goto类似。
函数:
小写字母开头的包在本包可见,大写字母开头的包在外部可见。
func(arg ...int)//传递int类型的不定参数。
func(arg ...interface{})//传递不定类型的不定参数。
多返回值:定义时初始化,后面可以使用返回值变量,如果只有return,则自动返回之前的返回值变量
匿名函数:
由一个不带函数名的函数声明和函数体构成,可以直接赋值或执行。
闭包的用法:
func fun_test(i int)(func(a, b int)(ret bool , c int)){
ret, e := fun1(1, 2)
fmt.Println( "fun1 return is :", ret, e )
fun2 := func (a, b int) (ret bool, c int){
return a < b, i
}
return fun2
}
闭包使用匿名函数来实现的。
defer,panic,recover关键字处理异常
defer关键字无论是否发生异常都会调用。
panic,recover不是特别理解,留待后面用的时候在看。
面向对象编程
类型系统:go可以为任意类型定义方法:包括内置,当不包括指针。
type integer int:定义一个新的类型,以int为基础。
为类型定义新的方法:
func (a integer)Less(b int)bool{
//func后面的 a integer表示类型。如果方法中需要修改,则可以用a *integer
return a < b
}
go语言一般情况是值语义,只有数组切片,map,chanel,接口是引用语义。
go提供接口查询功能。检查一个对象是否实现某一接口。也可以检查对象是否是某一类型。
接口是可以自由组合的?如何调用。
并发编程
go关键字可以实现并发。
channel:gocoroutine之前的通信通道。是类型安全的,只能够传递一种类型。
channel的读写操作对携程来说都是阻塞的。需要再数据被写入或读取后才向下执行。类似于阻塞时的套接字。
异步处理多个套接字或者channel,可以使用select。
channel可以设置缓存,在缓冲被填满前都不好被阻塞。
可以是range从带缓冲的通道中读多个内容。
可以利用select自己增加一个通道的超时机制。
目前需要多核运行需要设置环境变量:runtime.GOMAXPROCS(4)。
出让时间片,暂停协程运行函数:Gosched。
go提供两种锁。读写锁和单一锁。
sync的once可以保证一个函数在所有的协程中(也就是全局)只被调用一次。防止多个协程对一个借口的调用。
网络编程
net的Dial函数对套接字,连接等操作进行了封装,可以选择协议,并且发起连接。除此之外还有很多分支的Dial系列接口,可以完成更丰富的操作。
go在底层封装了http的客户端和服务前端的库。
go支持rpc。net\rpc包能够支持远程调用。
gob是一个可以对数据结构进行序列化的工具。rpc内部就是使用gob。
go的net/rpc/json提供JSON-RPC。
go的encoding/json标准库,开发者可以轻松的使用go程序生成和解析json。
go编写json比较方便,可以自动将结构体的变量名编码为key,将值转化为value。(我想在c中实现的想法)
解码未知结构可以使用map。
工程管理
go提供丰富的命令行,可以完成很多工作:代码检查,格式,等。
高级话题
reflect提供放射