超级苦工
阅读 52
《快学 Go 语言》第 4 课 —— 低调的数组

Go 语言里面的数组其实很不常用,这是因为数组是定长的静态的,一旦定义好长度就无法更改,而且不同长度的数组属于不同的类型,之间不能相互转换相互赋值,用起来多有不方便之处。

切片是动态的数组,是可以扩充内容增加长度的数组。当长度不变时,它用起来就和普通数组一样。当长度不同时,它们也属于相同的类型,之间可以相互赋值。这就决定了数组的应用领域都广泛地被切片取代了。

不过也不可以小瞧数组,在切片的底层实现中,数组是切片的基石,是切片的特殊语法隐藏了内部的细节,让用户不能直接看到内部隐藏的数组。切片不过是数组的一个包装,给顽固的数组装上了灵活的翅膀,让石头也可以展翅飞翔。

仅仅是上面纯文字的说明,读者肯定会感觉很懵。下面让我们来看具体的实例。

数组变量的定义

我们先试一下只申明类型,不赋初值。这时编译器会给数组默认赋上「零值」。数组的零值就是所有内部元素的零值。

package main

import "fmt"

func main() {
    var a [9]int
    fmt.Println(a)
}

------------
[0 0 0 0 0 0 0 0 0]


下面我们看看另外三种变量定义的形式, 效果都是一样的

package main

import "fmt"

func main() {
    var a = [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    var b [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    c := [8]int{1, 2, 3, 4, 5, 6, 7, 8}
    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
}

---------------------
[1 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9 10]
[1 2 3 4 5 6 7 8]

数组的访问

接下来我们使用下标来简单操作一下数组,这个数组里存的是数字的平方值

package main

import "fmt"

func main() {
    var squares [9]int
    for i := 0; i < len(squares); i++ {
        squares[i] = (i + 1) * (i + 1)
    }
    fmt.Println(squares)
}

--------------------
[1 4 9 16 25 36 49 64 81]

数组的下标越界检查(高阶知识)

上面的代码中我们注意到可以使用内置函数 len() 来直接获取数组的长度。数组的长度是编译期确定的,当我们使用 len() 函数访问数组的长度属性时,编译器在背后偷偷把它替换成了整数值。

package main

import "fmt"

func main() {
    var a = [5]int{1,2,3,4,5}
    a[101] = 255
    fmt.Println(a)
}

-----
./main.go:7:3: invalid array index 101 (out of bounds for 5-element array)


上面的代码运行结果说明了 Go 语言会对数组访问下标越界进行编译器检查。有一个重要的问题是,如果下标是一个变量,Go 是如何检查下标越界呢?变量需要在运行时才可以决定是否越界,Go 是如何办到的呢?

package main

import "fmt"

func main() {
    var a = [5]int{1,2,3,4,5}
    var b = 101
    a[b] = 255
    fmt.Println(a)
}

------------
panic: runtime error: index out of range

goroutine 1 [running]:
main.main()
    /Users/qianwp/go/src/github.com/pyloque/practice/main.go:8 +0x3d
exit status 2


答案是 Go 会在编译后的代码中插入下标越界检查的逻辑,所以数组的下标访问效率是要打折扣的,比不得 C 语言的数组访问性能。

数组赋值

同样的子元素类型并且是同样长度的数组才可以相互赋值,否则就是不同的数组类型,不能赋值。数组的赋值本质上是一种浅拷贝操作,赋值的两个数组变量的值不会共享。

package main

import "fmt"

func main() {
    var a = [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    var b [9]int
    b = a
    a[0] = 12345
    fmt.Println(a)
    fmt.Println(b)
}

--------------------------
[12345 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9]


从上面代码的运行结果中可以看出赋值后两个数组并没有共享内部元素。如果数组的长度很大,那么拷贝操作是有一定的开销的,使用的时候一定需要注意。下面我们尝试使用不同长度的数组赋值会有什么结果

package main

import "fmt"

func main() {
    var a = [9]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
    var b [10]int
    b = a
    fmt.Println(b)
}

--------------------------
./main.go:8:4: cannot use a (type [9]int) as type [10]int in assignment


可以看出不同长度的数组之间赋值是禁止的,因为它们属于不同的类型。

数组的遍历

数组除了可以使用下标进行遍历之外,还可以使用 range 关键字来遍历,range 遍历提供了下面两种形式。

package main

import "fmt"

func main() {
    var a = [5]int{1,2,3,4,5}
    for index := range a {
        fmt.Println(index, a[index])
    }
    for index, value := range a {
        fmt.Println(index, value)
    }
}

------------
0 1
1 2
2 3
3 4
4 5
0 1
1 2
2 3
3 4
4 5


考虑到切片的内容太多,我们将独立一节专门讲解切片,下一节将是 Go 语言的极有价值的一节,读者一定要努力搞清楚每一个细节。

阅读《快学 Go 语言》更多章节,用微信扫一扫上面的二维码关注公众号「码洞」

关注下面的标签,发现更多相似文章
评论
相关推荐
NANEA莱妮雅小肌蛋面膜,睡出来的天生丽质

护肤品行业永远不缺变化,有些变化是真的能带来好处的,有些变化是为了创新而创新,而NANEA莱妮雅意大利腊菊小肌蛋清肤面膜的变化,则是在创新的基础上为广大女性带来精致护肤实实在在好处的。 这一刻,抓住夜...

百年品牌NANEA莱妮雅——在服务中传递态度,在产品中演绎匠心

品牌历史沉淀,自然经典再现。百年来,NANEA莱妮雅一直为时尚年轻、简约轻奢品牌定位而努力进步,将天然植萃护肤理念传扬给更多人,这也已经成为品牌在护肤领域中不断耕耘的不竭动力和宗旨。 百年品牌NANE...

《快学 Go 语言》第 13 课 —— 并发与安全

来源: 知乎 原文: 《快学 Go 语言》第 13 课 —— 并发与安全 上一节我们提到并发编程不同的协程共享数据的方式除了通道之外还有就是共享变量。虽然 Go 语言官方推荐使用通道的方式来共享数据,...

《快学 Go 语言》第 12 课 —— 通道

来源: 知乎 原文: 《快学 Go 语言》第 12 课 —— 通道 不同的并行协程之间交流的方式有两种,一种是通过共享变量,另一种是通过队列。Go 语言鼓励使用队列的形式来交流,它单独为协程之间的队列...

《快学 Go 语言》第 11 课 —— 千军万马跑协程

来源: 知乎 原文: 《快学 Go 语言》第 11 课 —— 千军万马跑协程 协程和通道是 Go 语言作为并发编程语言最为重要的特色之一,初学者可以完全将协程理解为线程,但是用起来比线程更加简单,占用...

测试发布

测试文章发布...

《快学 Go 语言》第 10 课 —— 错误与异常

来源: 知乎 原文: 《快学 Go 语言》第 10 课 —— 错误与异常 Go 语言的异常处理语法绝对是独树一帜,在我见过的诸多高级语言中,Go 语言的错误处理形式就是一朵奇葩。一方面它鼓励你使用 C...

《快学 Go 语言》第 9 课 —— 接口

来源: 知乎 原文: 《快学 Go 语言》第 9 课 —— 接口 接口是一个对象的对外能力的展现,我们使用一个对象时,往往不需要知道一个对象的内部复杂实现,通过它暴露出来的接口,就知道了这个对象具备哪...

《快学 Go 语言》第 8 课 —— 结构体

来源: 知乎 原文: 《快学 Go 语言》第 8 课 —— 结构体 本节我们要开讲 Go 语言在数据结构上最重要的概念 —— 结构体。如果说 Go 语言的基础类型是原子,那么结构体就是分子。分子是原子...

《快学 Go 语言》第 7 课 —— 字符串

来源: 知乎 原文: 《快学 Go 语言》第 7 课 —— 字符串 字符串通常有两种设计,一种是「字符」串,一种是「字节」串。「字符」串中的每个字都是定长的,而「字节」串中每个字是不定长的。Go 语言...

《快学 Go 语言》第 6 课 —— 字典

来源: 知乎 原文: 《快学 Go 语言》第 6 课 —— 字典 字典在数学上的词汇是映射,将一个集合中的所有元素关联到另一个集合中的部分或全部元素,并且只能是一一映射或者多对一映射。&lt;img ...

《快学 Go 语言》第 5 课 —— 灵活的切片

来源: 知乎 原文: 《快学 Go 语言》第 5 课 —— 灵活的切片 切片无疑是 Go 语言中最重要的数据结构,也是最有趣的数据结构,它的英文词汇叫 slice。所有的 Go 语言开发者都津津乐道地...

《快学 Go 语言》第 4 课 —— 低调的数组

来源: 知乎 原文: 《快学 Go 语言》第 4 课 —— 低调的数组 Go 语言里面的数组其实很不常用,这是因为数组是定长的静态的,一旦定义好长度就无法更改,而且不同长度的数组属于不同的类型,之间不...

《快学 Go 语言》第 3 课 —— 分支与循环

来源: 知乎 原文: 《快学 Go 语言》第 3 课 —— 分支与循环 程序 = 数据结构 + 算法上面这个等式每一个初学编程的同学都从老师那里听说过。它并不是什么严格的数据公式,它只是对一般程序的简...

《快学 Go 语言》第 2 课 —— 变量基础

来源: 知乎 原文: 《快学 Go 语言》第 2 课 —— 变量基础 任何一门语言里面最基础的莫过于变量了。如果把内存比喻成一格一格整齐排列的储物箱,那么变量就是每个储物箱的标识,我们通过变量来访问计...

《快学 Go 语言》第 1 课 —— Hello World

来源: 知乎 原文: 《快学 Go 语言》第 1 课 —— Hello World Go 语言的 Logo最初 Go 语言的 Logo 是一只可爱的地鼠,地鼠昼伏夜出的习性让它显得很有 Geek 范。...

从零开始学调优-Java 全技术栈 性能调优超清原画无密点击自行下载

从零开始学调优-Java 全技术栈 性能调优超清原画无密【点击自行下载】为什么说:性能调优技术一直是市场上的香饽饽,是面试考察关键的一环,是工作中技术能力的分水岭?用最接地气话回答就是:掌握性能优化,...

体系课-数据可视化入门到精通-打造前端差异化竞争力完整无密

体系课-数据可视化入门到精通-打造前端差异化竞争力完整无密【点击自行下载】首门微体系课,不谦虚的讲,全网打着灯笼也找不到这么精炼、系统、实用的数据可视化课程,通过学习课程,不管是数据报表、数据大屏、移...

Java架构师成长直通车完整无密云盘分享

Java架构师成长直通车完整无密云盘分享【点击下载】 国内外一线大厂技术大咖与某课网组成专家团队12个月磨一剑千万级电商项目从0到1到100全过程涵盖Java程序员不同成长阶段的问题及优选解决方案 #...

测试图片

...