Go语言入门[五] 数组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uE0k2SlY-1692522170722)(D:\Study\notes\Go\golang.jpeg)]

指针

  • Go语言的指针部分和C/C++大致相同,如果有过学习C/C++指针部分,那你已经明白了大多数情况下指针的用法,这里只指出Go语言指针与其它语言不同的地方

  • Go语言中指针无法进行位移和运算,它的作用从C/C++中的无所不能,在Go中更像是变为了存储变量地址的变量。虽然如此,它的作用也非常重要。因为在值传递中,它可以减少内存的损耗(地址的内存损耗十分之少)

  • 指针的一般使用如下所示

package main

import "fmt"

func main() {
    str := "Hello World !"
    var strP *string
    strP = &str
    *strP = "Hello Codey !"
    fmt.Println("指针strP的地址为", strP)
    fmt.Println("指针strP指向的值为", *strP)
    fmt.Println("指针str的地址为", &str)
    fmt.Println("指针str的值为", str)
}
  • 运行结果
$ go run hello.go
指针strP的地址为 0xc00005c270
指针strP指向的值为 Hello Codey !
指针str的地址为 0xc00005c270
指针str的值为 Hello Codey !

数组

数组的声明和初始化

  • 数组的一般声明形式诸如
var arrayName [size]dataType
//  var 数组名字 [数组大小]数据类型
  • 还记得前面的章节中,我们有说过不同数据类型变量的初始值吗?在数组初始化时,他们都会拥有自己的默认值
package main
import "fmt"
func main() {
    var number [10]int
    for i:=0; i< 10; i++ {
        fmt.Println("i = ",i,"number = ",number[i])
    }
}
  • 这里我们只对number进行了声明而并未赋值,最后的输出结果也证明,数组中的元素在声明时就已经有了自己的默认值
$ go run hello.go
i =  0 number =  0
i =  1 number =  0
i =  2 number =  0
i =  3 number =  0
i =  4 number =  0
i =  5 number =  0
i =  6 number =  0
i =  7 number =  0
i =  8 number =  0
i =  9 number =  0
  • 当然我们也可以像其它语言那样使用类似集合的形式来声明数组
var numbers = [5]int{1, 2, 3, 4, 5}
numbers := [5]int{1, 2, 3, 4, 5}
  • 当我们不知道数组具体大小时,我们也可以使用...代替数组的长度,由编译器根据元素个数自主推断数组的长度
var a = [...]int{5,6,7,8,9,10}
a := [...]int{777,222,666,777,888}
  • 但如果我们需要在初始化的时候指定某个元素的值Go语言也为我们提供了一种简便的方式
var number  = [...]int{1:5,6:8,9:666}
balance := [8]float{0:9.99,5:6.66}
  • 我们只需要用诸如数组索引:指定元素值的方式就可以指定元素的赋值。如果我们声明的是一个不定数组,最后数组的长度会是我们指定的数组索引+1的。但如果我们已经指定了数组的长度,数组索引就无法大于等于数组长度了,否则会报越界异常

数组的比较

  • Go语言中数组的比较只会涉及两个部分

    • 数组的长度是否相等

    • 数组中对应值是否完全相同

  • 当然数组能够比较的基础是二者是相同类型。需要注意的是,Go语言中数组的大小也是类型的一部分,不同大小的数组并不兼容[5]int[10]int不相同的类型,所以无法比较(在GolandIDE会直接提示类型不匹配)

  • 下面的例子展示了两个数组的比较方式

package main
import "fmt"
func main() {
    var a [2]int
    var c = [2]int{1, 2}
    var d = [...]int{1, 2}
    fmt.Println("a == c ? ", a == c)
    fmt.Println("c == d ?", c == d)
}
  • 运行结果
$ go run hello.go
a == c ? false
c == d ? true

切片(Slice)

  • 切片是对数组的抽象。在特定场景中,数组这样不可变长度的性质就变得不太实用。为此,Go语言提供了一种使用灵活,功能更为强大的类型——切片(可以理解为动态数组)

切片的声明和初始化

  • 切片的声明形式和数组类似,更像是声明了一个没有长度的数组
var slice_name []type
// var 切片名 []切片类型
  • 与数组不同的是,数组中的元素在声明时就有了自己的默认值,而切片没有零值。我们如果想要使用一个切片,必须要在使用前进行初始化。切片声明后它的值就是nil(空指针),这是因为它的底层实现就是一个指向数组的指针,在给它存入数组的地址之前,它的值只能是nil

  • 我们可以使用make()函数对切片进行初始化

package main

import (
    "fmt"
)

func main() {
    var a []int
    fmt.Println("初始化前:", a)
    a = make([]int, 5, 10)
    fmt.Println("初始化后:", a)
    a[4] = 5
    fmt.Println("  赋值后:", a)
    a[5] = 6
    fmt.Println("赋值后:", a)
}
  • 运行结果如下所示
$ go run hello.go
初始化前: []
初始化后: [0 0 0 0 0]
  赋值后: [0 0 0 0 5]
panic: runtime error: index out of range [5] with length 5

goroutine 1 [running]:
main.main()
        D:/Study/notes/Go/hello.go:14 +0x192
exit status 2
  • 对于一个make函数,它的参数如下所示
make(切片类型,切片长度,切片容量)
  • 切片长度:切片中元素的数量。当切片长度被指定后,相应长度的元素都会拥有零值。在例子中我们可以看到,我们指定a这个切片的长度为5,相应就有5个元素拥有零值

  • 切片容量:切片引用数组的长度。切片的容量一般都会大于等于长度,容量也会随着长度的增长而增长(动态的来源)。我们在初始化一个切片的时候其实就是给切片引用了一个数组,容量就是这个数组的长度,如果切片长度将要超过切片的容量,它就会让切片引用一个更大容量的数组来存放这些元素(有点像C++STLvector的实现方式,先创建一个小容量数组,其后通过倍增,迁移数据)

  • 我们可以通过一个小实验观察容量的变化过程

package main

import (
    "fmt"
)

func main() {
    var a = []int{1, 2, 3, 4, 5}
    fmt.Printf("a的地址%p,a的长度%d,a的容量%d\n", a, len(a), cap(a))
    a = append(a, 6)
    fmt.Printf("a的地址%p,a的长度%d,a的容量%d\n", a, len(a), cap(a))
    a = append(a, 7, 8)
    fmt.Printf("a的地址%p,a的长度%d,a的容量%d\n", a, len(a), cap(a))
    b := []int{9, 10, 11}
    a = append(a, b...)
    fmt.Printf("a的地址%p,a的长度%d,a的容量%d\n", a, len(a), cap(a))
}
  • 运行结果如下所示
$ go run hello.go
a的地址0xc000012300,a的长度5,a的容量5
a的地址0xc00001a1e0,a的长度6,a的容量10
a的地址0xc00001a1e0,a的长度8,a的容量10
a的地址0xc0000220a0,a的长度11,a的容量20
  • 结果验证了我们的猜想。其中len()函数可以让我们获取切片中元素的数量(切片长度),cap()函数可以让我们获取引用的数组长度(切片容量)

切片的追加

  • 上一节我们使用了一个从未见过的函数append(),实际上它就是本节要讲述的内容。切片是一个动态的数组,意味着我们可以像C++vector那样在尾部对它追加元素

  • 一般的使用形式诸如append(切片,待添加值)

package main

import (
    "fmt"
)

func main() {
    var a = []int{1, 2, 3, 4, 5}
    a = append(a, 6)
    fmt.Println(a)
    a = append(a, 7, 8)
    fmt.Println(a)
    b := []int{9, 10}
    a = append(a, b...)
    fmt.Println(a)
}
  • 运行结果
$ go run hello.go
[1 2 3 4 5 6]
[1 2 3 4 5 6 7 8]
[1 2 3 4 5 6 7 8 9 10]
  • 如例所示,如果我们待添加的元素是一个数组或切片,我们可以使用...使其一次性添加到切片的末尾

切片的截取

  • 如果你学过python,这段对你来说一定不会陌生。 我们可以使用诸如切片名[begin:end:max]的形式创建一个新的切片,其中,截取的片段是一个左闭右开区间[begin,end)max是新切片的容量
package main

import (
    "fmt"
)

func main() {
    var a = []int{1, 2, 3, 4, 5}
    fmt.Println("a[1:3]=", a[1:3])
    //截取元素a[1]-a[2],创建一个容量和长度都为2的切片
    fmt.Println("a[1:]=", a[1:])
    //截取元素a[1]-末尾,创建一个容量和长度都为4的切片
    fmt.Println("a[:3]=", a[:3])
    //截取元素开头-a[2],创建一个容量和长度都为3的切片
}

参考链接

我爱学习网 | Go语言中的数组

我爱学习网 |Go语言中的切片

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值