美文网首页Go程序员
Golang 中的数组 (array) 和切片 (slice)

Golang 中的数组 (array) 和切片 (slice)

作者: 老码农不上班 | 来源:发表于2017-10-08 18:06 被阅读109次

huangwenwei - 字里行间 | Golang 中的数组 (array) 和切片 (slice)

中文描述约定
array: 数组
slice: 切片

来做个测试,不在机器上运行下面的代码,请给出输出

vals :make([]int, 5)
for i:= 0; i < 5; i++ {
    vals = append(vals, i)
}
fmt.Println(vals)

如果你猜测的结果是 [0 0 0 0 0 1 2 3 4],恭喜你答对了。
为啥么正确答案不是 [0 1 2 3 4] 呢?
大部分像我一样 Golang 初学者都会打错这道测试题,在这篇文章中,我们来探讨一下为什么不是我们期望的输出结果以及 slice 数据类型中 capacity 和 length 的用法。

Slices VS Arrays

初学时可能会把 Golang 中数组和切片的区别,但是如果习惯了使用切片,将会极大地优化代码;
数组和切片有很多不同点,但在这里我们记住它们之间最大的区别就是:固定的数组大小是数组声明时的一部分,而切片可以有一个动态的大小。那么在实际的编码中是如何体现的呢?例如 val a [10]int, 这个数组有一个固定的大小 10 ,却不能改变长其度;如果我们调用 len(a),返回 10,因为长度就是数组的一部分;这就导致一个问题,如果有数组长度超过 10 的需求,你必须新建另外一个数组对象,譬如 val b [11]int, 并把数组 a 的值拷贝到数组 b
,在某种场景下固定长度的数组非常有用,但是通常我们长度灵活的数组,需要一种“没有固定大小的数组”,最直接的做法是声明数组时给足够大的长度,例如:

var vals [20]int
for i := 0; i < 5; i++ {
    vals[i] = i * i
}
subsetLen := 5

fmt.Println("The subset of our array has a length of:" subsetLen)

// Add a new item to our array
vals[subsetLen] = 123
subsetLen++
fmt.Print("The subset of our array has a length of:", subsetLen)

上面的例子中,我们声明数组时设置了其长度为 20 ,通过一个变量我们“设置”其长度为 5 ,我们往其加了一个元素之后, subset 自增 1,数组长度就变成了 6
粗略地说,这就是切片的原理,通过设置一个值来限定数组的最大长度,在上述例子中为 20 ;同时切片还有一个值来表示数组元素的真实长度,在上述例子中为 subsetLen ;故切片中有 capacity cap 和 length len 两个概念。切片的内部实现基于数组,但是使用方式更灵活、运行更高效。cap 限定了切片中元素个数增加的上限,通过 append 函数,我们不需关心数组底层的个数上限。

回到我们的测试题

明白了数组和切片的概念和不同点之后,我们再次解释一下测试题。
make 函数能够声明一个切片,第一个参数表示类型,第二个参数表示类型的长度,第三个参数为可选参数,表示类型的容纳上限;
make([]int, 5) 表示我们要新建一个长度为 5 的切片,切片的默认容纳上限(capacity)和长度一致。但是 append 函数表示切片增加一个元素,那么该切片的容纳上限将同时增加,并在切片的末尾新增一个元素。也就是默认的切片值为 [0 0 0 0 0] 增加一个元素将会被放置在在第五个元素后面,所以运行结果如下:

vals := make([]int, 5)  
fmt.Println("Capacity was:", cap(vals))  
for i := 0; i < 5; i++ {
    vals = append(vals, i)
    fmt.Println("Capacity is now:", cap(vals))
}
fmt.Println(vals)
// output: [0 0 0 0 0 0 1 2 3 4]

如果修改为下面的代码,则输出为 [0, 1, 2, 3, 4]

vals := make([]int, 5)  
for i := 0; i < 5; i++ {  
      vals[i] = i
}
fmt.Println(vals)

代码不够简洁,改造一下:我们把 vals 的长度设置为 0 ,容纳上限为 5

vals := make([]int, 0, 5)
for i := 0; i < 5; i++ {
    vals = appen(vals, i)
}
fmt.Println(vals)

最后,如果能知道切片的上限,建议最好给 make 函数加上第三个参数。

相关文章

  • Golang 中的数组 (array) 和切片 (slice)

    huangwenwei - 字里行间 | Golang 中的数组 (array) 和切片 (slice) 中文描述...

  • Golang之数组和切片

    引用 数组、字符串和切片 Go数组中的索引问题 深入解析 Go 中 Slice 底层实现 Golang 入门 : ...

  • Golang 中数组(Array)和切片(Slice)的区别

    Go 中数组的长度是不可改变的,而 Slice 解决的就是对不定长数组的需求。他们的区别主要有两点。 区别一:初始...

  • Go 语言极速入门3 - 内建容器

    内建容器Array 数组Slice 切片,是 Array 的一个 viewMap 映射 一、Array 数组 [1...

  • Learn Golang in 21 Days - Day 10

    Learn Golang in 21 Days - Day 10 知识点 切片Slice Slice是对数组的抽象...

  • 深入理解 Go Slice

    原文地址:深入理解 Go Slice 是什么 在 Go 中,Slice(切片)是抽象在 Array(数组)之上的特...

  • go数组切片

    go数组切片 主要知识点 数组(array)类型和切片(slice)都属于集合类的类型;他们最重要的不同是:数组类...

  • Golang 数组 切片

    Golang 数组和切片 go提供了相应数据类型来存储多个相同类型的元素。它们分别是数组和slice切片。其中,切...

  • golang切片

    切片是对数组的抽象 slice 总是指向底层的一个 array。 slice 是一个指向 array 的指针,这是...

  • js数组操作

    1、切片 slice()slice 方法返回一个 Array 对象,参数:start,截取数组开始下标。end截止...

网友评论

本文标题:Golang 中的数组 (array) 和切片 (slice)

本文链接:https://www.haomeiwen.com/subject/fuhyyxtx.html