GO的第五天,复合数据类型---数组、Slice

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

内容简介:数组是一个由默认情况下,数组的每个元素都被初始化为元素类型对应的零值,对于数字类型来说就是0。在数组字面值中,如果在数组的

数组

数组是一个由 固定长度 的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,因此在 Go 语言中很少直接使用数组。和数组对应的类型是Slice(切片),它是可以增长和收缩动态序列。

默认情况下,数组的每个元素都被初始化为元素类型对应的零值,对于数字类型来说就是0。

var a [3]int
var q [3]int = [3]int{1,2,3}
var r [3]int = [3]int{1,2}

fmt.Println(r[2]) // 0

在数组字面值中,如果在数组的 长度位置 出现的是“...”省略号,则表示数组的长度是根据 初始化值的个数 来计算。因此,上面q数组的定义可以简化为:

var q := [...]int{1,2,3}
fmt.Printf("%T\n", q)   // [3]int

数组的 长度 是数组类型的一个组成部分,因此[3]int和[4]int是两种不同的数组类型。数组的长度必须是 常量表达式 ,因为数组的长度需要在 编译阶段 确定。

q := [3]int{1,2,3}
q = [3]int{1,2,3,4} // cannot use [4]int literal (type [4]int) as type [3]int in assignment

定义了一个含有100个元素的数组r,最后一个元素被初始化为-1,其它元素都是用0初始化:

r := [...]int{99:-1}

如果一个数组的元素类型是可以相互比较的,那么数组类型也是可以相互比较的,这时候我们可以直接通过==比较运算符来比较两个数组,只有当两个数组的所有元素都是相等的时候数组才是相等的。不相等比较运算符!=遵循同样的规则。

a := [2]int{1, 2}
b := [...]int{1, 2}
c := [2]int{1, 3}
fmt.Println(a == b, a == c, b == c) // "true false false"
d := [3]int{1, 2}
fmt.Println(a == d) // compile error: cannot compare [2]int == [3]int

如果我们要使用函数对数组进行操作,我们传入的应该是指针,而不是数组。这是因为,当函数 参数变量 接收的是一个 复制的副本 ,并不是原始调用的变量。因为函数参数传递的机制导致传递 大的数组类型将是低效的 ,并且对数组参数的任何的修改都是发生在复制的数组上,并不能直接修改调用时原始的数组变量。

下面的函数用于给[32]byte类型的数组清零:

func zero(ptr *[32]byte) {
    for i := range ptr {
        ptr[i] = 0
    }
}

虽然通过指针来传递数组参数是高效的,而且也允许在函数内部修改数组的值,但是数组依然是 僵化的类型 ,因为数组的类型包含了僵化的长度信息。上面的zero函数并不能接收指向[16]byte类型数组的指针,而且也没有任何添加或删除数组元素的方法。由于这些原因,除了像SHA256这类需要处理特定大小数组的特例外, 数组依然很少用作函数参数 ;相反,我们一般使用slice来替代数组。

Slice

Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个slice类型一般写作[]T,其中T代表slice中元素的类型;slice的语法和数组很像,只是 没有固定长度 而已。

数组和slice之间有着紧密的联系。一个slice是一个 轻量级的数据结构 ,提供了访问数组子序列(或者全部)元素的功能,而且slice的底层确实 引用一个数组对象 。一个slice由三个部分构成: 指针、长度和容量 。指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。 长度对应slice中元素的数目 ;长度不能超过容量, 容量一般是从slice的开始位置到底层数据的结尾位置 。内置的len和cap函数分别返回slice的长度和容量。

slice的切片操作s[i:j],其中0 ≤ i≤ j≤ cap(s),用于创建一个新的slice,引用s的从第i个元素开始到第j-1个元素的子序列。新的slice将只有j-i个元素。如果i位置的索引被省略的话将使用0代替,如果j位置的索引被省略的话将使用len(s)代替。

下面代码和图片更直观的解释了slice:

months := [...]string{1: "January", /* ... */, 12: "December"}

Q2 := months[4:7]
summer := months[6:9]

fmt.PrintIn(Q2)  // ["April" "May" "June"]

fmt.PrintIn(summer) // ["June" "July" "August"]

GO的第五天,复合数据类型---数组、Slice

如果slice超出了容量cap(s)的上限将导致一个panic异常,但是超出len(s)则是意味着扩展了slice,因为新slice的长度会变大:

fmt.Println(summer[:20]) // panic: out of range

endlessSummer := summer[:5] // extend a slice (within capacity)
fmt.Println(endlessSummer)  // "[June July August September October]"

和数组不同的是, slice之间不能比较 ,因此我们不能使用==操作符来判断两个slice是否含有全部相等元素。不过标准库提供了高度优化的bytes.Equal函数来判断两个字节型slice是否相等([]byte),但是对于其他类型的slice,我们必须自己展开每个元素进行比较:

func equal(x, y []string) bool {
    if len(x) != len(y) {
        return false
    }
    for i := range x {
        if x[i] != y[i] {
            return false
        }
    }
    return true
}

为何slice不直接支持比较运算符呢?这方面有两个原因:

  1. 一个slice的元素是间接引用的,一个slice甚至可以包含自身。
  2. 因为slice的元素是间接引用的,一个固定的slice值(指slice本身的值,不是元素的值)在不同的时刻可能包含不同的元素,因为底层数组的元素可能会被修改。

关于slice更多的信息,下次再详细的写吧。

参考

《GO语言圣经》


以上所述就是小编给大家介绍的《GO的第五天,复合数据类型---数组、Slice》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

绝对价值

绝对价值

[美] 伊塔马尔·西蒙森 艾曼纽·罗森 / 钱峰 / 中国友谊出版公司 / 2014-7 / 45.00元

绝对价值指的是经用户体验的产品质量,即使用某件产品或者享受某项服务的切实感受。 过去,消费就像是押宝。一件商品好不好,一家餐馆的环境如何,没有亲身体验过消费者无从得知,只能根据营销人员提供的有限信息去猜测。品牌、原产地、价位、广告,这些重要的质量线索左右着消费者的选择。 然而,互联网和新兴科技以一种前所未有的速度改变了商业环境。当消费者可以在购买前查看到交易记录和消费者评价,通过便捷的......一起来看看 《绝对价值》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具