go学习笔记
println
printf
基本类型里,字符区分byte和rune。byte占用一个字节,对应ascii符号,类型也会被输出为uint8。rune类型则是为了处理unicode而出现,对应UTF-8格式。
string可以直接 '+'拼接,也可以用sprintf拼接。
go里面的string不能直接修改,修改要先强制转换[]byte或者[]rune。
go不允许隐式转换,也就是说int32+int64这种行为要明确转换同一类型,并且应该低转高。
要把其他类型转换成string,可以用sptintf,也可以用strconv。比如:
strconv.FormatInt(int64, fmt),参数1是int64数值,参数2是进制
strconv.FormatFloat(num,fmt,point,size) 参数2是指定浮点数显示格式,参数3指定保留几位小数点,参数4指定32/64位
同样的,strconv还可以把string转换为int等类型:
strconv.ParseInt(str, base,size) 参数2为进制,参数3为大小(32/64)。但是字符串未必符合需要,所以这个函数返回值其实是两个。
int,err = strconv.ParseInt(str, base,size)
strconv.ParseFloat(str, size)
运算符:golang中,++和--是单独的语句,不是运算符,只能单独使用。比如a++ 是可以的,但是var b = a++是错误的。此外,go中只有后缀,没有前缀,++i是非法的。
if:golang里if语句需要注意:首先,if后面的条件不需要括号,比如 if a>0 && a<3 {
} 左括号必须紧挨着条件,不能换行。else if,else同样要求。
其次,if还有一个特殊的地方: 在与条件下,如果第一个判断就为false,那么后面的条件不会执行。这一点很值得注意。比如 if a<0 && test_func(),如果a不满足,那么后面的函数就不会再执行了。 类似的,在或条件下,第一个判断为True后面的就不再执行了。
此外,if语句的条件里可以定义变量: if a:=30;a>20 这样的变量类似for循环的变量,都是局部变量。
go语言没有三目运算符。
除了类Cfor循环,go也支持基于范围的for循环。
for idx,value := range source fmt.println(value)
idx是索引,value是值。基于范围的for循环在面对诸如中英文混合的字符串读取时会方便的多(汉字3字节)
switch:go的switch语句里,case允许一次写多个,比如 case 1,3,5,7,这样相当于把几个case写到了一起。
case 1,3,5,7,9: // break //可以不写 case 2,4,6,8,0: // break
甚至可以写表达式。如果 case写表达式,那switch后面就不需要写判断变量了。
go语言为了兼容c的设计(不写break就可以穿透到下一case),还有fallthrough关键词,可以穿透到下一case。写法顶替break即可
此外,循环外可以加label,在循环内break label就可以跳出指定循环。
数组的长度也是定义的一部分。[4]int和[5]int就是两个不同的类型。go的数组是定长,需要变长用slice切片。在赋值时,不想指定长度可以用[...]来代替。除此之外,数组还支持用索引来初始化赋值。例如:
a := [...]int{1:1,3:5} //0 1 0 5的数组,冒号前是索引
在go里,基本类型和数组都是值类型,而切片/map/通道都是引用类型。例如:
var arr = []int{1,2,3} //切片 arr2 = arr //此时再修改arr,arr2也会改变
切片可以用类似数组的方式赋值,同时由于它基于数组,所以还可以用数组来初始化赋值
a := [5]int{2,34,1,23,334} //数组
b := a[:] //切片 :表示获取所有值,因为没写前后标,需要的话可以写
c := a[1:3] //注意含前不含后
此外,也可以用切片定义切片
---- ----------------------
切片在直接声明但不赋值时长度为0,值是nil,在这种情况下, a:=[]int{} 声明后
尝试赋值a[0]是非法操作,想塞入值只能用append:'
append(a, 2,44,5) //塞入元素可以是任意长,也可以合并两个切片
在声明时用make( []T, size,cap) 就可以直接声明出长度为size的切片,这样就可以直接赋值了。
a := make( []int, 5 )
----- -----
还有一个值得注意的点,和c++的vector有点类似,切片也分长度len和容量cap,长度就是切片内元素的个数,而容量是当前切片对应底层数组里,切片首元素到底层数组末尾的长度。
s := []int{1,2,3,4,5} //长度5,容量5
s1 := s[1:] //长度为4,容量为4
s2 := s[1:3] //长度2,容量4,因为底层数组

关于append的扩容策略,假设是新生成的切片,第一次append后容量为1,第二次为2,第三次为4;按2的幂扩容。如果新容量大于2倍旧容量,那最终容量就是新申请容量。如果旧切片长度小于1024,那最终容量就直接翻倍;如果长度大于1024,最终容量就是旧容量循环加1/4直到满足需求。
-------
由于切片是引用类型,所以用一个切片赋值等于另一切片时,修改一者也会影响另一者。为了避免这一问题,可以用copy而不是直接等于
sliceA := []int{1,2,3,4} sliceB := make([]int, 4)copy(sliceB, sliceA)
在删除时,由于go的切片没有直接提供删除,所以只能用拼凑的方式实现:
//假设a是切片,要删除索引为2的元素 a = append(a[:2], a[3:]...) //最后一个元素后省略号要加
----- -------
map是一个无序键值对, 声明方式是map[keytype]valueType 。和切片类似,可以使用make来初始化,直接声明时值为nil。
var map1 = make(map[string]string) //或者直接赋值 var map1 =map[string]string{ "name":Tom", //用冒号 "age":"1999" }
在逐条打印时可以使用for range,range 的两个参数旧对应了键和值。此外,map可以直接用键值对来赋值。
var map1 = map[string]string map1["name"] = "Tom"
查找需要注意:map1["name"] ,输入后会有两个返回值:
value ,ok := map1["name"] //第一个返回值是value,第二个是是否成功取值,true/false
删除则使用delete函数。delete(map,key)即可删除一个键值对。
-----一点延申:
切片和map自然是可以嵌套的,比如说,一个元素是map的切片:
var a = make( []map[string]string ,3 ,3) 这样就声明了一个切片,元素是键值string的map. 但此时所有元素都是nil,给每个元素赋值前还需要a[0] = make(map[string]string)来初始化。
关于go的设计,我是这样理解的,首先var a = make([]map[string]string, 3)时,元素类型已经声明了,每个元素都是map[string]string。但是此时声明以后,元素值都是map对应的零,也就是nil。那么给每个元素赋值时,就还需要用一次make来给每个元素初始化。
也可以声明一个map,map的键/值是切片,例如:
var a = make(map[string][]string)
这样就声明并初始化了一个key为string,value为string切片的map。一个string键就可以对应多个string值了。
浙公网安备 33010602011771号