本文已参与「开源摘星计划」,欢迎正在阅读的你加入。
学习了前两篇,我们掌握了go的声明以及控制流,这让我们可以使用go语言来编写复杂的逻辑。
作为操控计算机进行计算的编程语言,免不了要和大量的数据进行交互。选择合适高效的数据结构就格外重要了。
go语言通过精心设计,提供了一组高效且常用的数据结构,让我们来一起学习下。
这里先介绍下go的pointer(指针)和struct(结构体),这两位可以更好的帮助我们操作和组织数据。
package main
import "fmt"
func main() {
i, j := 42, 2701
p := &i
fmt.Println(*p)
*p = 21
fmt.Println(i)
p = &j
*p = *p / 37
fmt.Println(j)
}
pointer指针,就是保存了“目标内存地址”的变量,通过&符号来获取目标内存地址,通过*符号来访问目标。很简单吧,我们来看下struct(结构体)。
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
定义一个名为Vertex(顶点)的结构体,它具有两个属性:X和Y,分别代表其在二维坐标系中x轴和y轴的值。通过{}花括号给这个结构体赋值来初始化创建:v := Vertex{1, 2}。通过.来进行结构体属性的访问:v.X。
通过结构体,我们可以表示一个具有多属性的复杂对象,并可以有效的将数据组织起来。比如我们要开发一个学生管理系统,就可以定义一个“学生”结构体,然后它具有“性别,年龄,民族,籍贯”等等属性。
下面,介绍第一个常用的数据结构:数组array。
package main
import "fmt"
func main() {
var a [2]string // 定义包含2个string类型元素的数组
a[0] = "Hello" // 赋值
a[1] = "World"
fmt.Println(a[0], a[1]) // 取值
fmt.Println(a)
primes := [6]int{2, 3, 5, 7, 11, 13} // 定义包含6个int类型的数组并初始化赋值
fmt.Println(primes)
}
如果没有初始化赋值,使用var关键字来声明;如果带初始化赋值,可以使用:=来自动确定类型。
go语言的数组有个很方便、很有趣的特性:切片slices。
package main
import "fmt"
func main() {
primes := [6]int{2, 3, 5, 7, 11, 13} // 这里声明了大小,所以是数组
var s []int = primes[1:4] // 获取第2个到第4个元素,遵循“左闭右开”
s[0] = 1111 // 改变切片的值
fmt.Println(s)
fmt.Println(primes) // 原数组的值也改变
}
通过[:]语法,获取了primes数组的一个切片。注意!切片并没有创建一个新的数组,只是指向原数组片段的“指针”。改变切片的内元素的值,将会影响原数组。
通过len函数获取数组或者切片的长度,通过cap函数获取数组或者切片的容量capacity。
package main
import "fmt"
func main() {
s := []int{2, 3, 5, 7, 11, 13} // 这里没有声明大小,所以是切片
printSlice(s)
s = s[:0]
printSlice(s)
s = s[:4]
printSlice(s)
s = s[2:]
printSlice(s)
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
go数组或者切片的“容量”是个很有意思的概念。如上,每个切片都有显式的长度,还包含隐式的容量。容量实际上代表的就是切片所指向的数组的长度。
上面介绍了指针、结构体和第一个重要的数据结构:数组以及它的好伙伴切片。
下一章,我们会介绍一些切片的好朋友,它们帮助我们更好的使用切片。