Go语言学习笔记(三) 集合类型

数组

数组中包含的每个数据被称为数组元素(element),一个数组包含的元素个数被称为数组的长度。

[32]byte // 长度为32的数组,每个元素为一个字节
[2*N] struct { x, y int32 } // 复杂类型数组
[1000]*float64 // 指针数组
[3][5]int // 二维数组
[2][2][2]float64 // 等同于[2]([2]([2]float64))

元素访问

for i := 0; i < len(array); i++ {
fmt.Println("Element", i, "of array is", array[i])
}
for i, v := range array {
fmt.Println("Array element[", i, "]=", v)
}

在Go语言中数组是一个值类型(value type)

package main
import "fmt"
func modify(array [10]int) {
array[0] = 10 // 试图修改数组的第一个元素
fmt.Println("In modify(), array values:", array)
}
func main() {
array := [10]int{1,2,3,4,5} // 定义并初始化一个数组,未定义的元素为零值,即0
modify(array) // 传递给一个函数,并试图在函数体内修改这个数组内容
fmt.Println("In main(), array values:", array)
}
该程序的执行结果为:
In modify(), array values: [10 2 3 4 5 0 0 0 0 0]
In main(), array values: [1 2 3 4 5 0 0 0 0 0]

可以用指针的概念解决这个问题

package main
import "fmt"
func modify(array *[10]int) {//接收指针值
array[0] = 10 // 试图修改数组的第一个元素
fmt.Println("In modify(), array values:", array)
}
func main() {
array := [10]int{1,2,3,4,5} // 定义并初始化一个数组,未定义的元素为零值,即0
modify(&array) // 传递指针
fmt.Println("In main(), array values:", array)
}
该程序的执行结果为:
In modify(), array values: &[10 2 3 4 5 0 0 0 0 0]
In main(), array values: [10 2 3 4 5 0 0 0 0 0]

如果你使用多维数组,有一些内容你必须录入:

a := [2][2]int{ [2]int{1,2}, [2]int{3,4} }
a := [2][2]int{ [...]int{1,2}, [...]int{3,4} }//Go 会自动统计元素的个数。
a := [2][2]int{ {1,2}, {3,4} }

切片slice

slice 与array 接近,但是在新的元素加入的时候可以增加长度。slice 总是指向底层的一个array。slice 是一个指向array 的指针,这是其与array 不同的地方;slice 是引用类型,这意味着当赋值某个slice 到另外一个变量,两个引用会指向同一个array。例如,如果一个函数需要一个slice 参数,在其内对slice 元素的修改也会体现在函数调用者中,这和传递底层的array 指针类似。

创建数组切片

创建数组切片的方法主要有两种——基于数组和直接创建。

基于数组:

func main() {
// 先定义一个数组
var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// 基于数组创建一个数组切片
var mySlice []int = myArray[:5]
fmt.Println("Elements of myArray: ")
for _, v := range myArray {
fmt.Print(v, " ")
}
fmt.Println("\nElements of mySlice: ")
for _, v := range mySlice {
fmt.Print(v, " ")
}
fmt.Println()
}
运行结果为:
Elements of myArray:
1 2 3 4 5 6 7 8 9 10
Elements of mySlice:
1 2 3 4 5

Go语言支持用myArray[first:last]这样的方式来基于数组生成一个数组切片

基于myArray的所有元素创建数组切片:
mySlice = myArray[:]
基于myArray的前5个元素创建数组切片:
mySlice = myArray[:5]
基于从第5个元素开始的所有元素创建数组切片:
mySlice = myArray[5:]

直接创建:
并非一定要事先准备一个数组才能创建数组切片。Go语言提供的内置函数make()可以用于灵活地创建数组切片。当然,事实上还会有一个匿名数组被创建出来,只是不需要我们来操心而已。

创建一个初始元素个数为5的数组切片,元素初始值为0:
mySlice1 := make([]int, 5)
创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间:
mySlice2 := make([]int, 5, 10)
直接创建并初始化包含5个元素的数组切片:
mySlice3 := []int{1, 2, 3, 4, 5}
直接创建并初始化包含4个元素的数组切片:
mySlice3 := []interface{}{3,"str", []int{3,4},func() {fmt.Println()}}

len() 和 cap()函数

因为切片(Slice)是数组上的抽象。它实际上使用数组作为底层结构体.len()函数返回切片中存在的元素数量,其中cap()函数返回切片(Slice)的容量(大小),即可容纳多少个元素。以下是解释切片(Slice)的用法的示例:

package main
import "fmt"
func main() {
   var numbers = make([]int,3,5)
   printSlice(numbers)
}
func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
当上述代码编译和执行时,它产生以下结果:
len=3 cap=5 slice=[0 0 0]

append()和copy()函数

切片(Slice)允许使用append()函数增加切片的容量(大小)。使用copy()函数,将源切片的内容复制到目标切片。以下是示例:

package main

import "fmt"

func main() {
   var numbers []int
   printSlice(numbers)

   /* append allows nil slice */
   numbers = append(numbers, 0)
   printSlice(numbers)

   /* add one element to slice*/
   numbers = append(numbers, 1)
   printSlice(numbers)

   /* add more than one element at a time*/
   numbers = append(numbers, 2,3,4)
   printSlice(numbers)

   /* create a slice numbers1 with double the capacity of earlier slice*/
   numbers1 := make([]int, len(numbers), (cap(numbers))*2)

   /* copy content of numbers to numbers1 */
   copy(numbers1,numbers)
   printSlice(numbers1)   
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
Go
当上述代码编译和执行时,它产生以下结果:

len=0 cap=0 slice=[]
len=1 cap=2 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=8 slice=[0 1 2 3 4]
len=5 cap=16 slice=[0 1 2 3 4]

字典map

map 可以认为是一个用字符串做索引的数组(在其最简单的形式下)。下面定义了map 类型,用于将string(月的缩写)转换为int – 那个月的天数。一般定义map 的方法是:map[<from type>]<to type>

monthdays := map[string]int{
"Jan": 31, "Feb": 28, "Mar": 31,
"Apr": 30, "May": 31, "Jun": 30,
"Jul": 31, "Aug": 31, "Sep": 30,
"Oct": 31, "Nov": 30, "Dec": 31,   //逗号是必须的
}

留意,当只需要声明一个map 的时候,使用make 的形式:

monthdays := make(map[string]int)

当在map 中索引(搜索)时,使用方括号。例如打印出12 月的天数:

fmt.Printf("%d\n",monthdays["Dec"])

当对array、slice、string 或者map 循环遍历的时候,range 会帮助你,每次调用,它都会返回一个键和对应的值。

year := 0
for _, days := range monthdays {   键没有使用,因此用_, days
year += days
}
fmt.Printf("Numbers of days in a year:%d\n", year)

向map 增加元素,可以这样做:

monthdays["Undecim"] = 30   //添加一个月
monthdays["Feb"] = 29   //年时重写这个元素

检查元素是否存在,可以使用下面的方式:

var value int
var present bool
value, present =monthdays["Jan"]   //如果存在,present 则有值true

或者更接近Go 的方式

v, ok := monthdays["Jan"]   //“逗号ok”形式

也可以从map 中移除元素:

delete(monthdays, "Mar")   //删除"Mar" 

通常来说语句delete(m, x) 会删除map 中由m[x] 建立的实例。

猜你喜欢

转载自blog.csdn.net/weixin_36251021/article/details/80705638