Go指南-数组与切片

栏目: IT技术 · 发布时间: 4年前

内容简介:在Golang中,数组与切片是两个概念,数组用的比较少,切片用的比较多,也更为常见,理解了它们之间的关系,能够帮助我们减少一些奇奇怪怪的问题。一切还要从这张图讲起..这张图中说明了数组和切片的核心区别,同时也是本文讲解的重点:

在Golang中,数组与切片是两个概念,数组用的比较少,切片用的比较多,也更为常见,理解了它们之间的关系,能够帮助我们减少一些奇奇怪怪的问题。

一切还要从这张图讲起..

Go指南-数组与切片

这张图中说明了数组和切片的核心区别,同时也是本文讲解的重点:

1.数组的声明需要指定长度,而切片可指定也可不指定。

2.切片本质是对数组一个引用,切片改变,数组也会改变。

3.切片包含三个部分:数组引用、长度属性、容量属性。长度属性指的是切片的元素数量,决定了可读取数据的上限;而容量属性指的切片的最大元素数量,决定切片了扩展的上限。

1.数组和切片的声明

// 数组的声明
var arr [3]int
arr[0] = 1


// 切片的声明,通过var关键字
var slic []int

// 切片的声明,通过make关键字
slic := make([]int, 0, 0)

复制代码

2.切片是对数组的引用

func main() {
	// 底层数组声明
	names := [4]string{
		"John",
		"Paul",
		"George",
		"Ringo",
	}
	fmt.Println(names)
	
	// 获取切片,a,b共享一个数组
	a := names[0:2]
	b := names[1:3]
	fmt.Println(a, b)
	
	// 改变切片b,会改变底层数组,所以a也变了
	b[0] = "XXX"
	fmt.Println(a, b)
	fmt.Println(names)
}

复制代码

3.切片的长度与容量

切片长度属性指的是切片的元素数量,决定了可读取数据的上限;而容量属性指的切片的最大元素数量,决定切片了扩展的上限

长度的计算: 即切片的元素数量,这个比较好理解。

容量的计算: 从切片的第一个元素起,到底层数组的最后一个元素,即为切片的容量。

栗子一:

func sliceLenAndCap() {
	names := [6]string{
		"John",
		"Paul",
		"George",
		"Ringo",
		"Richer",
		"Amy",
	}

	a := names[2:4]
  fmt.Println(a)
  // 切片a包含George和Ringo元素,所以长度为2
  fmt.Println(len(a))  
  // 从切片的第一个元素算起,即George,底层包含的元素是George到Amy,有4个,所以cap为4
	fmt.Println(cap(a))  
}
复制代码

长度和容量在声明切片时的作用,栗子二:

// 声明了一个长度和容量都为0的切片
// 与 num1 := []int{} 等价
var num1 []int

// 声明了一个长度为0,容量为3的切片,其底层数组包含三个元素,值都是0
num1 := make([]int, 0, 3)

// 声明一个长度为1,容量为3的切片,可以看到其元素值是0
num2 := make([]int, 1, 3)
fmt.Println(num2)  // [0]
复制代码

切片的容量属性:单凭一个长度属性,Go编译器无法知道是否需要对底层数组进行扩容,所以还需要一个容量属性辅助判断。

栗子三:

func sliceAddElem() {
  // 一开始容量为2,即底层数组只有两个元素
	num1 := make([]int, 0, 2)
	fmt.Printf("num1 %p", num1)  //  0xc000020090

  // 添加元素时,发现添加的元素数量超过底层数组的长度,所以创建了一个新的数组,并修改切片的引用,让它指向新数组
	num1 = append(num1, 1, 2, 3, 4)  // 0xc000018140
	fmt.Printf("num1 %p", num1)
}
复制代码

4.切片和数组的注意事项

4.1 切片再强调

  • 切片是对数组的引用,所以它本身并不会存储元素
  • append等方法针对的对象是切片,不是数组,需小心

4.2 Golang数组和 C语言 数组的区别

1.C语言的数组名是一个元素的地址,代表指针型常量,所以不能将一个数组赋值给另一个数组;而 Go 的数组是一个值,所以可以赋给另外一个数组,且赋值时是拷贝所有元素到新数组中。

func arrayCopy() {
	arr1 := [3]int{1, 2, 3}
	arr2 := arr1
	fmt.Println(arr2)  // [1 2 3]
	arr1[0] = -1
	fmt.Println(arr1)  // [-1 2 3]
	fmt.Println(arr2)  // [1 2 3]
}

复制代码

2.在Golang中,如果将一个数组传入某个函数,在函数内部接收到的是数组的副本而非指针。如果想传入指针,有两种做法,一是显式加上指针,第二就是传递切片(推荐做法)

func elemAdd(arr [3]int) {
	for idx, _ := range arr{
		arr[idx] += 1
	}
	fmt.Println("new", arr) // [2, 3, 4]
}

func elemAddTest() {
	num1 := [3]int{1, 2, 3}
	elemAdd(num1)
	fmt.Println(num1) // [1, 2, 3]
}

// 1.显式加上指针
func elemAddByPoint(arr *[3]int) {
	for idx, _ := range arr{
		arr[idx] += 1
	}
	fmt.Println("new", arr) // &[2, 3, 4]
}

func elemAddByPointTest() {
	num1 := [3]int{1, 2, 3}
	elemAddByPoint(&num1)
	fmt.Println(num1) // [2, 3, 4]
}

// 2.传递切片
func elemAddBySlice(arr []int) {
	for idx, _ := range arr{
		arr[idx] += 1
	}
	fmt.Println("new", arr) // [2, 3, 4]
}

func elemAddBySliceTest() {
	num1 := []int{1, 2, 3}
	elemAddBySlice(num1)
	fmt.Println(num1) // [2, 3, 4]
}

复制代码

4.3 之前遇到的一个小坑

func sliceTest() {
	// 声明两个切片,一开始两个切片的地址是不一样的
	var t = make([]int, 0, 10)
	var s = make([]int, 0, 10)

	fmt.Printf("addr:%p \tlen:%v content:%v\n", t, len(t), t);  // addr:0xc00009a000       len:0 content:[]
	fmt.Printf("addr:%p \tlen:%v content:%v\n", s, len(s), s);  // addr:0xc00009a050       len:0 content:[]

	t = append(s, 1, 2, 3, 4)

	// 后面t和s的地址是一样的,但是指向的值却不一样
	fmt.Printf("addr:%p \tlen:%v content:%v\n", t, len(t), t); // addr:0xc00009a050       len:4 content:[1 2 3 4]
	fmt.Printf("addr:%p \tlen:%v content:%v\n", s, len(s), s); // addr:0xc00009a050       len:0 content:[]
}
复制代码

这是因为 t = append(s, 1, 2, 3, 4) 这条语句向切片s的底层数组增加了四个元素(仅仅是底层数组变了),并让t指向这个底层数组,所以t和s的地址一样。而且由于新切片被赋值给t,而不是s,所以t的内容是 [1, 2, 3, 4] ,s的内容是 []


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Definitive Guide to Django

The Definitive Guide to Django

Adrian Holovaty、Jacob Kaplan-Moss / Apress / 2007-12-06 / CAD 45.14

Django, the Python-based equivalent to the Ruby on Rails web development framework, is presently one of the hottest topics in web development today. In The Definitive Guide to Django: Web Development ......一起来看看 《The Definitive Guide to Django》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具