【Go自学第二节】Go中的数组与切片区别;切片的底层逻辑

文章介绍了Golang中数组和切片的区别与用法。数组是长度固定的数据项序列,而切片是动态的,基于数组的引用类型。切片可以通过append()函数增加元素,其长度和容量可通过len()和cap()获取。在函数传递时,数组传递值,切片传递引用。切片的修改会直接影响底层数组。
摘要由CSDN通过智能技术生成

在Golang中,数组属于聚合类型,而切片属于引用类型。其实切片的底层逻辑就是用数组实现的,所以我们首先需要了解数组。


一、数组 Array

数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。

相对于去声明 number0, number1, ..., number99 的变量,使用数组形式 numbers[0], numbers[1] ..., numbers[99] 更加方便且易于扩展。

数组元素可以通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推。

数组初始化

1、直接赋值

var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}//等价于
balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

2、不确定数组长度时

var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}//等价于
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

3、指定位置初始化,其余位置补0

//  将索引为 1 和 3 的元素初始化
balance := [5]float32{1:2.0,3:7.0}

 二、切片 Slice

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

切片实际上是一种结构体,结构如下:

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

他由指向底层数组的指针、长度len、和容量cap组成。 

切片初始化

s := [] int {1,2,3 } //直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3。cap=len=3。
s := arr[:] //初始化切片 s,是数组 arr 的引用。
s := arr[startIndex:endIndex] //将 arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片。
s := arr[startIndex:] //缺省 endIndex 时将表示一直到 arr 的最后一个元素。
s := arr[:endIndex] //缺省 startIndex 时将表示从 arr 的第一个元素开始。
s := s[startIndex:endIndex] //通过切片 s 初始化切片 s1
s := make([]type, len)//通过内置函数 make() 初始化切片 s,[]int 标识为其元素类型为 int 的切片,length为长度
s := make([]int,length,capacity) //length为长度,capacity为容量

 len() 和 cap() 函数

切片是可索引的,并且可以由 len() 方法获取长度。切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。

package main

import "fmt"

func main() {
   var numbers = make([]int,3,5)

   printSlice(numbers)
}

func printSlice(x []int){
   fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
//输出 len=3 cap=5 slice=[0 0 0]
}

 append()函数

s := make([]int, 5) 
s = append(s, 6, 7) 
fmt.Println(len(s), cap(s)) // 输出7 10 
s = append(s, 8, 9, 10, 11) 
fmt.Println(len(s), cap(s))//输出11 20 
s5 := make([]int, 5) 
s6 := []int{11, 22, 33, 44, 55, 66} 
s := append(s5, s6...) 
fmt.Println(s, len(s), cap(s))//输出[0 0 0 0 0 11 22 33 44 55 66] 11 12 

 总结

 array和slice有以下区别

1、初始化方式

2、array定长,slice动态变化长度

3、当切片和数组作为参数在函数(func)中传递时,数组传递的是值,而切片传递的是指针。因此当传入的切片在函数中被改变时,函数外的切片也会同时改变。相同的情况,函数外的数组则不会发生任何变化。当切片和数组作为参数在函数(func)中传递时,数组传递的是值,而切片传递的是指针。因此当传入的切片在函数中被改变时,函数外的切片也会同时改变。相同的情况,函数外的数组则不会发生任何变化。


切片的底层逻辑 

切片自己不拥有任何数据。它只是底层数组的一种表示。对切片所做的任何修改都会反映在底层数组中。

func main() {  
    darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
    dslice := darr[2:5]
    fmt.Println("array before",darr)
    for i := range dslice {
        dslice[i]++
    }
    fmt.Println("array after",darr) 
}

编译运行结果

array before [57 89 90 82 100 78 67 69 59]  
array after [57 89 91 83 101 78 67 69 59]  

 同理切片的长度是切片中的元素数。切片的容量是从创建切片索引开始的底层数组中元素数。

func main() {
	fruitarray := [...]string{"apple", "orange", "grape", "mango", "water melon", "pine apple", "chikoo"}
	fruitslice := fruitarray[1:3]
	fmt.Println(fruitslice)
	fmt.Printf("length of slice %d capacity %d\n", len(fruitslice), cap(fruitslice))
	fruitslice = fruitslice[:cap(fruitslice)]
	fmt.Println("After re-slicing length is", len(fruitslice), "and capacity is", cap(fruitslice))
	fmt.Println(fruitslice)
}

编译运行结果

[orange grape]
length of slice 2 capacity 6
After re-slicing length is 6 and capacity is 6
[orange grape mango water melon pine apple chikoo]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Weber77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值