go学习笔记

print

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值了。

posted @ 2025-06-30 23:21  namezhyp  阅读(12)  评论(0)    收藏  举报