青训营笔记【go语言基础】

89 阅读4分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 1 天

前言

这是我学习go语言的第一天,初步学习go语言就可以感受到go语言集合了许多语言的特性,但是又在此的基础上有更好的发展。作为一个初学者,这里主要基于课程和《Go语言圣经(中文版)》记录学习go的笔记。

程序结构

变量

在go语言中声明变量的一般语法是这样:var 变量名字 变量类型 = 表达式

其中变量类型 和**= 表达式** 可缺少其中一个,当缺少变量类型时会从表达式中自动推导变量类型,如果表达式省略则会自动填充默认值

简短变量声明

在go语言中还有一种声明方式,它以“名字 := 表达式”形式声明变量

anim := gif.GIF{LoopCount: nframes}
freq := rand.Float64() * 3.0
t := 0.0

这种声明方式更加简短,而且这里有个地方要注意,变量可能已经声明过了,那么这里就只有赋值了

基础数据类型

整型

Go语言的数值类型包括几种不同大小的整数、浮点数和复数。每种数值类型都决定了对应的大小范围和是否支持正负符号。让我们先从整数类型开始介绍。

Go语言同时提供了有符号和无符号类型的整数运算。这里有int8、int16、int32和int64四种截然不同大小的有符号整数类型,分别对应8、16、32、64bit大小的有符号整数,与此对应的是uint8、uint16、uint32和uint64四种无符号整数类型。

这里还有两种一般对应特定CPU平台机器字大小的有符号和无符号整数int和uint;其中int是应用最广泛的数值类型。这两种类型都有同样的大小,32或64bit,但是我们不能对此做任何的假设;因为不同的编译器即使在相同的硬件平台上可能产生不同的大小。

字符串

字符串中的切片域python中的相似,值得注意的是go中字符串可以用==和<进行比较;比较通过逐个字节比较完成的,因此比较的结果是字符串自然编码的顺序。

字符串的值是不可变的:一个字符串包含的字节序列永远不会被改变,当然我们也可以给一个字符串变量分配一个新字符串值。可以像下面这样将一个字符串追加到另一个字符串:

s := "left foot"
t := s
s += ", right foot"

这并不会导致原始的字符串值被改变,但是变量s将因为+=语句持有一个新的字符串值,但是t依然是包含原先的字符串值。

fmt.Println(s) // "left foot, right foot"
fmt.Println(t) // "left foot"

因为字符串是不可修改的,因此尝试修改字符串内部数据的操作也是被禁止的:

s[0] = 'L' // compile error: cannot assign to s[0]

不变性意味着如果两个字符串共享相同的底层数据的话也是安全的,这使得复制任何长度的字符串代价是低廉的。同样,一个字符串s和对应的子字符串切片s[7:]的操作也可以安全地共享相同的内存,因此字符串切片操作代价也是低廉的。在这两种情况下都没有必要分配新的内存。

复合数据类型

数组

go语言中的数组与其它语言的数组大致一样。go语言中数组的定义为var 变量名称 [长度/...]变量类型 = [长度/...]变量类型{}

数组的长度在编译时就要确定,其中“...”省略号,则表示数组的长度是根据初始化值的个数来计算。

而且go中数组相同长度和变量类型相同的数组可以用==比较

map

go语言中map的定义有两种方式:

ages := make(map[string]int) // mapping from strings to ints
ages := map[string]int{
    "alice":   31,
    "charlie": 34,
}

使用内置的delete函数可以删除元素:

delete(ages, "alice") // remove element ages["alice"]

所有这些操作是安全的,即使这些元素不在map中也没有关系;如果一个查找失败将返回value类型对应的零值,例如,即使map中不存在“bob”下面的代码也可以正常工作,因为ages["bob"]失败时将返回0。

但是map中的元素并不是一个变量,因此我们不能对map的元素进行取址操作:

_ = &ages["bob"] // compile error: cannot take address of map element

禁止对map元素取址的原因是map可能随着元素数量的增长而重新分配更大的内存空间,从而可能导致之前的地址无效。