数组,切片

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)
}

  

猜你喜欢

转载自www.cnblogs.com/ACGame/p/11875932.html