1、数组
数组属于值类型。
1)声明
var 数组变量名 [元素数量]Type
- 数组变量名:数组声明及使用时的变量名。
- 元素数量:数组的元素数量,可以是一个表达式,但最终通过编译期计算的结果必须是整型数值,元素数量不能含有到运行时才能确认大小的数值。
- Type:可以是任意基本类型,包括数组本身,类型为数组本身时,可以实现多维数组。
默认情况下,数组的每个元素都会被初始化为元素类型对应的零值,对于数字类型来说就是 0,同时也可以使用数组字面值语法,用一组值来初始化数组。
在数组的定义中,如果在数组长度的位置出现“...”省略号,则表示数组的长度是根据初始化值的个数来计算。
示例:
package main import "fmt" func main() { var a [3]int for i := 0; i < len(a); i++{ fmt.Printf("%d, %d\n", i, a[i]) } var b = [3]int{1, 2} fmt.Println("----------------------------") for i := 0; i < len(b); i++{ fmt.Printf("%d, %d\n", i, b[i]) } c := [...]int{1, 2, 3} fmt.Println("----------------------------") for i := 0; i < len(c); i++{ fmt.Printf("%d, %d\n", i, c[i]) } }
2)比较两个数组是否相等
如果两个数组类型相同(包括数组的长度,数组中元素的类型)的情况下,我们可以直接通过较运算符(==
和!=
)来判断两个数组是否相等,只有当两个数组的所有元素都是相等的时候数组才是相等的,不能比较两个类型不同的数组,否则程序将无法完成编译。
数组类型相同的数组之间可以互相赋值。
3)多维数组
示例:
package main import "fmt" func output(str string, arr [4][2]int) { fmt.Printf("ArrName: %s\n", str) for i := 0; i < 4; i++{ for j := 0; j < 2 ; j++ { fmt.Printf("%d, ", arr[i][j]) } fmt.Println() } } func main() { // 声明一个二维整型数组,两个维度的长度分别是 4 和 2 var a [4][2]int output("a", a) // 使用数组字面量来声明并初始化一个二维整型数组 b := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}} output("b", b) // 声明并初始化数组中索引为 1 和 3 的元素 c := [4][2]int{1: {20, 21}, 3: {40, 41}} output("c", c) // 声明并初始化数组中指定的元素 d := [4][2]int{1: {0: 20}, 3: {1: 41}} output("d", d) }
2、切片
切片(slice)是对数组的一个连续片段的引用,所以切片是一个引用类型。Go语言中切片的内部结构包含地址、大小和容量,切片一般用于快速地操作一块数据集合。
1)从数组或切片生成新的切片
从连续内存区域生成切片是常见的操作,格式如下:
slice [开始位置 : 结束位置]
- slice:表示目标切片对象;
- 开始位置:对应目标切片对象的索引;
- 结束位置:对应目标切片的结束索引。
从数组或切片生成新的切片拥有如下特性:
- 取出的元素数量为:结束位置 - 开始位置;
- 取出元素不包含结束位置对应的索引,切片最后一个元素使用 slice[len(slice)] 获取;
- 当缺省开始位置时,表示从连续区域开头到结束位置;
- 当缺省结束位置时,表示从开始位置到整个连续区域末尾;
- 两者同时缺省时,与切片本身等效;
- 两者同时为 0 时,等效于空切片,一般用于切片复位。
示例:
package main import "fmt" func main() { var a = [3]int{1,2,3} fmt.Println(a[1:2]) fmt.Println(a[:3]) fmt.Println(a[0:]) }
2)直接声明切片
除了可以从原有的数组或者切片中生成切片外,也可以声明一个新的切片,每一种类型都可以拥有其切片类型,表示多个相同类型元素的连续集合,因此切片类型也可以被声明,切片类型声明格式如下:
var name []Type
切片是动态结构,只能与 nil 判定相等,不能互相判定相等。
声明新的切片后,可以使用 append() 函数向切片中添加元素。
示例:
package main import "fmt" func main() { var a []int // 声明但未使用的切片的默认值是 nil var b = []int{} // 已经分配了内存 fmt.Println(a == nil) // true fmt.Println(b == nil) // false }
3)使用make()函数构造切片
如果需要动态地创建一个切片,可以使用 make() 内建函数,格式如下:
make( []Type, size, cap )
其中 Type 是指切片的元素类型,size 指的是为这个类型分配多少个元素,cap 为预分配的元素数量,这个值设定后不影响 size,只是能提前分配空间,降低多次分配空间造成的性能问题。
注意:使用 make() 函数生成的切片一定发生了内存分配操作,但给定开始与结束位置(包括切片复位)的切片只是将新的切片结构指向已经分配好的内存区域,设定开始与结束位置,不会发生内存分配操作。
示例:
package main import "fmt" func main() { a := make([]int, 2, 10) fmt.Println(a) fmt.Println("len=", len(a)) fmt.Println("cap=", cap(a)) }
4)添加元素
Go语言的内建函数 append() 可以为切片动态添加元素,在使用 append() 函数为切片动态添加元素时,如果空间不足以容纳足够多的元素,切片就会进行“扩容”,此时新切片的长度会发生改变。
尾部添加元素示例:
package main import "fmt" func main() { var a []int a = append(a, 1) // 追加1个元素 a = append(a, 1, 2) // 追加多个元素 a = append(a, []int{1, 2, 3}...) // 追加一个切片 fmt.Println(a) }
头部添加元素示例:
package main import "fmt" func main() { var a = []int{1, 2, 3} a = append([]int{1}, a...) // 在开头添加1个元素 a = append([]int{1, 2}, a...) // 在开头添加1个切片 fmt.Println(a) }
切片中间插入元素示例:
package main import "fmt" func main() { var a = []int{1, 2, 3, 4, 5} // 在第2个位置插入一个切片 a = append(a[:2], append([]int{998, 999}, a[2:]...)...) /* 每个添加操作中的第二个 append 调用都会创建一个临时切片,并将 a[i:] 的内容复制到新创建的切片中, 然后将临时创建的切片再追加到 a[:i] 中。 */ fmt.Println(a) }
5)切片复制
Go语言的内置函数 copy() 可以将一个数组切片复制到另一个数组切片中,如果加入的两个数组切片不一样大,就会按照其中较小的那个数组切片的元素个数进行复制。
copy() 函数的使用格式:copy( destSlice, srcSlice []T) int
其中 srcSlice 为数据来源切片,destSlice 为复制的目标(也就是将 srcSlice 复制到 destSlice),来源和目标的类型必须一致,copy() 函数的返回值表示实际发生复制的元素个数。
示例:
package main import "fmt" func main() { slice1 := []int{1,2,3,4,5} slice2 := []int{100, 101, 102} count := copy(slice2, slice1) fmt.Println(count) count = copy(slice1, slice2) fmt.Println(count) }