GO语言入门指南:基础语法和常用特性解析(切片&Map) | 青训营

74 阅读9分钟

已经在其他语言中很熟悉的编程基础不再重复,只写那些较为特殊的语法规则,此篇笔记主要介绍切片和Map,也是GO编程中经常使用到的

切片

切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。切片也叫"动态数组",与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

切片是一个引用类型,它的内部结构包含地址长度容量。切片一般用于快速地操作一块数据集合。

可以声明一个未指定大小的数组来定义切片:

var identifier []type

或使用 make() 函数来创建切片:

var slice1 []type = make([]type, len)
​
也可以简写为
​
slice1 := make([]type, len)

也可以指定容量,其中 capacity 为可选参数。

make([]T, length, capacity)

这里 len 是数组的长度并且也是切片的初始长度。

切片初始化

s :=[]int {1,2,3 } 

直接初始化切片, [] 表示是切片类型, {1,2,3} 初始化值依次是 1,2,3,其 cap=len=3

s := arr[:] 

初始化切片 s,是数组 arr 的引用。

s := arr[startIndex:endIndex] 

将 arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片。

s :=make([]int,len,cap) 

通过内置函数 make() 初始化切片s[]int 标识为其元素类型为 int 的切片。

切片的长度和容量

切片拥有自己的长度和容量,我们可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量。

一个切片在未初始化之前默认为 nil,长度为 0

切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。

要检查切片是否为空,请始终使用len(s) == 0来判断,而不应该使用s == nil来判断。

切片的遍历方式和数组是一致的,支持索引遍历和for range遍历。

func main() {
    s := []int{1, 3, 5}
​
    for i := 0; i < len(s); i++ {
        fmt.Println(i, s[i])
    }
​
    for index, value := range s {
        fmt.Println(index, value)
    }
}

Map(集合)

Go语言中提供的映射关系容器为map,其内部使用散列表(hash)实现。

map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用。

Map 是无序的,遍历 Map 时返回的键值对的顺序是不确定的。

在获取 Map 的值时,如果键不存在,返回该类型的零值,例如 int 类型的零值是 0,string 类型的零值是 ""。

Map 是引用类型,如果将一个 Map 传递给一个函数或赋值给另一个变量,它们都指向同一个底层数据结构,因此对 Map 的修改会影响到所有引用它的变量。

Go语言中 map的定义语法如下:

map[KeyType]ValueType

其中,

  • KeyType:表示键的类型。
  • ValueType:表示键对应的值的类型。

map类型的变量默认初始值为nil,需要使用make()函数来分配内存。语法为:

make(map[KeyType]ValueType, [cap])

其中cap表示map的容量,该参数虽然不是必须的,但是我们应该在初始化map的时候就为其指定一个合适的容量。

// 创建一个空的 Map m := make(map[string]int)

// 创建一个初始容量为 8的 Map

scoreMap := make(map[string]int, 8)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100

也可以使用字面量创建 Map:

// 使用字面量创建 Map
m := map[string]int{
    "apple": 1,
    "banana": 2,
    "orange": 3,
}

获取元素:

// 获取键值对
v1 := m["apple"]
v2, ok := m["pear"]  // 如果键不存在,ok 的值为 false,v2 的值为该类型的零值

修改元素:

// 修改键值对
m["apple"] = 5

获取 Map 的长度:

// 获取 Map 的长度
len := len(m)

遍历 Map:

// 遍历 Map
for k, v := range m {
    fmt.Printf("key=%s, value=%d\n", k, v)
}

删除元素:

// 删除键值对
delete(m, "banana")

判断某个键是否存在

Go语言中有个判断map中键是否存在的特殊写法,格式如下:

value, ok := map[key]

举个例子:

func main() {
	scoreMap := make(map[string]int)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100
	// 如果key存在ok为true,v为对应的值;不存在ok为false,v为值类型的零值
	v, ok := scoreMap["张三"]
	if ok {
		fmt.Println(v)
	} else {
		fmt.Println("查无此人")
	}
}

具体编程中遇到的问题

在Go语言中,[4]int[]int是不同的类型。

[4]int是一个固定长度的数组,它具有4个整数元素。

[]int是一个切片,它是动态长度的数组。切片可以根据需要动态增长或缩小。

如果要将一个固定长度的数组转换为切片,可以使用切片操作符[:]。例如:

nums := [4]int{1, 2, 3, 4}
slice := nums[:]

这将创建一个切片slice,它引用了整个数组nums

如果要将[4]int类型的数组作为函数参数传递给接受[]int类型的参数的函数,可以将数组转换为切片,并将切片作为参数传递。例如:

func myFunction(nums []int) {
	// 函数体
}

nums := [4]int{1, 2, 3, 4}
myFunction(nums[:])

在这个例子中,将nums[:]传递给myFunction函数,它会接受一个[]int类型的切片参数。

map中的键是唯一的,每个键只能对应一个值。如果对同一个键赋值多次,最终的值将是最后一次赋值的结果。

需要注意的是,map是一个引用类型。当将一个map传递给函数或赋值给另一个变量时,它们都指向同一个底层的数据结构。因此,对map的修改将在所有引用中可见。

此外,map是无序的,这意味着遍历map的顺序是不确定的。如果需要按照特定顺序遍历键值对,可以先将键存储在一个切片中,然后对切片进行排序。

总结

学习完Go语言中切片(slice)和映射(map)的使用,我对它们的特点和用法有了更深入的了解。以下是我对这两个概念的总结:

切片(slice)是Go语言中一种动态数组的抽象。它是一个拥有长度和容量的可变序列,可以根据需要动态增长或缩小。切片的声明和初始化可以使用make函数或直接使用字面量。通过索引访问切片中的元素,切片可以使用切片运算符[:]获取一个子切片。切片的长度可以使用len()函数获取,容量可以使用cap()函数获取。

切片的特点:

  1. 切片是引用类型,底层是一个数组。
  2. 切片的长度可以动态改变。
  3. 切片的容量是指底层数组从切片的第一个元素到最后一个元素的长度。
  4. 当切片被追加的元素超过容量时,切片会自动扩容,容量翻倍。
  5. 如果切片没有被引用,则会被垃圾回收。

映射(map)是Go语言中一种无序的键值对集合。它使用哈希表实现,可以根据键快速检索值。映射的声明和初始化使用make函数,也可以使用字面量的方式。映射中的键必须是支持相等运算符的类型,值可以是任意类型。可以使用键来访问映射中的值,如果键不存在,则返回对应值类型的零值。

映射的特点:

  1. 映射是引用类型,底层是一个哈希表。
  2. 映射的长度可以使用len()函数获取。
  3. 映射是无序的,每次迭代映射的顺序是随机的。
  4. 映射的键必须是支持相等运算符的类型,值可以是任意类型。
  5. 使用delete()函数可以删除映射中的键值对。

切片和映射是Go语言中非常常用的数据结构,在实际开发中经常会用到。切片适用于动态增长的场景,而映射适用于需要通过键快速查找值的场景。掌握了切片和映射的使用,可以更高效地处理数据集合,并简化代码的编写。

关于学习切片和映射的思考和建议:

  1. 理解切片和映射的概念:在开始学习切片和映射之前,确保你对它们的概念和用途有一个清晰的理解。切片是一个动态数组,可以动态增长和缩减,而映射是一种键值对集合,用于存储和检索数据。
  2. 学习切片和映射的创建和初始化:了解如何创建和初始化切片和映射是基础。学习使用make函数和字面量来创建和初始化切片;学习使用make函数和字面量来创建和初始化映射。
  3. 掌握切片和映射的基本操作:学习使用索引和切片操作符来访问和修改切片中的元素;学习使用键来访问和修改映射中的值。还要了解如何使用内置的len和cap函数获取切片的长度和容量。
  4. 理解切片和映射的底层实现:了解切片和映射的底层数据结构和实现方式,对于理解它们的行为和性能有帮助。切片底层使用数组,映射底层使用哈希表。
  5. 学习切片和映射的高级操作:熟悉切片的切割、追加和复制操作;了解映射的遍历、删除和更新操作。还要学习如何处理切片和映射的空值和nil值。
  6. 实践练习和项目应用:通过编写一些小的练习程序和实际项目,加深对切片和映射的理解。实践中遇到的问题和挑战会帮助你更好地掌握它们的用法和特性。
  7. 阅读官方文档和参考资料:阅读Go语言官方文档中关于切片和映射的部分,了解它们的详细用法和注意事项。此外,还可以阅读其他优质的教程和博客文章,深入理解切片和映射的特性。

总的来说,学习切片和映射需要理解它们的概念、掌握基本操作、了解底层实现、并进行实践练习。通过持续的学习和实践,你将能够熟练地使用切片和映射来处理集合数据,并在Go语言的开发中发挥更大的作用。