Go的Slice和数组

Go的Slice和数组,第1张

 博客主页:🏆看看是李XX还是李歘歘 🏆

🌺每天分享一些包括但不限于计算机基础、算法等相关的知识点🌺

💗点关注不迷路,总有一些📖知识点📖是你想要的💗

⛽️今天的内容是     Go的Slice和数组     ⛽️💻💻💻

 相同之处 属于集合类的类型,值都可以用来存储某一种类型的元素;在内存布局中都是连续分配的。 区别 数组的长度固定;slice的值长度可变。数组长度在声明的时候就必须给定,并且之后不会再改变。slice类型的字面量中只有元素类型,没有长度(可以在使用make函数时候初始化时添加长度和容量),切片长度可以自动随着元素数量的增长而增长,但不会随着元素数量的减少而减少。

数组是值类型(值类型有基本数据类型,结构体类型);切片属于引用类型(引用类型:字典类型,通道类型,函数类型),引用类型不需要使用额外的内存并且比使用数组更有效率。

如果传递的参数是引用类型,那么就是“传引用”,如果传递的是值类型,那么就是“传值”(会把以前的数据复制一遍)

数组的长度=容量,不可改变;切片长度<=容量,动态扩容;

Slice源码

slice的容量和长度都是可以进行动态扩容的。

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

array:指向slice中第一个元素地址

len:slice长度

cap:slice容量

长度必须小于等于容量,通过len()和cap()函数分别返回slice的长度和容量。

关于长度和容量的定义,在源码中关于len()和cap()的定义如下:

// The len built-in function returns the length of v, according to its type:

// Array: the number of elements in v.

// Pointer to array: the number of elements in *v (even if v is nil).

// Slice, or map: the number of elements in v; if v is nil, len(v) is zero.

// String: the number of bytes in v.

// Channel: the number of elements queued (unread) in the channel buffer;

//          if v is nil, len(v) is zero.

// For some arguments, such as a string literal or a simple array expression, the

// result can be a constant. See the Go language specification's "Length and

// capacity" section for details.

func len(v Type) int

slice或者map:参数v中元素的个数,如果v是nil,则长度为0

// The cap built-in function returns the capacity of v, according to its type:

// Array: the number of elements in v (same as len(v)).

// Pointer to array: the number of elements in *v (same as len(v)).

// Slice: the maximum length the slice can reach when resliced;

// if v is nil, cap(v) is zero.

// Channel: the channel buffer capacity, in units of elements;

// if v is nil, cap(v) is zero.

// For some arguments, such as a simple array expression, the result can be a

// constant. See the Go language specification's "Length and capacity" section for

// details.

func cap(v Type) int

slice:当重新切片时,切片能够搜索到的最大长度。

在切片(slice)中,长度代表它包含的元素的个数(遍历时候,以len()为基准)容量代表从它的第一个元素开始计数,到其底层数组元素末尾的个数,所以说,len是永远小于等于cap的。

func main() {

   a := []int{0123456789}

   fmt.Println(len(a), cap(a))  //10 10

   b := a[3:4]

   fmt.Println(len(b), cap(b))  // 1 7

}

len(b)长度即4-3=1;cap(b)容量即10-3=7。

Slice的扩容 首先判断,如果新申请容量(cap)大于2倍的旧容量(old.cap),扩容后切片的容量(newcap)就是新申请的容量(cap);否则判断,如果旧切片的长度小于1024,则扩容后切片的容量(newcap)就是旧容量(old.cap)的两倍,即(newcap=doublecap);否则判断,如果旧切片长度大于等于1024,则扩容后切片的容量(newcap)从旧容量(old.cap)开始循环增加原来的1/4,即(newcap+=newcap/4),直到扩容后切片的容量(newcap)大于等于新申请的容量(cap),即(newcap>=cap);如果扩容后切片的容量(cap)计算值溢出,则最终容量(cap)就是新申请容量(cap)。 slice之append时原数组发生变化的问题 append函数

append用于往slice中添加元素或者合并两个slice,函数append()总是会增加slice的长度,而容量可能回改变,也可能不会改变,这取决于被 *** 纵切片的可用容量。

如果nums的cap够用,则会直接在nums指向的数组后面追加元素,返回的slice和原来的slice是同一个对象。显然,这种情况下原来的slice的值会发生变化!如果nums的cap不够用,则会创建一个新的底层数组空间用来存储数据,将被引用的现有的值复制到新数组里,再添加元素,返回指向新数组的slice。这时候原来的slice指向的数组并没有发生任何变化!

补充:为了更好的使用append()函数实现追加元素,为底层数组提供一定的保护,建议使用切片的第三个索引来限制新切片的容量。

切片是引用类型,可能多个切片使用同一个底层数组,对切片的内容进行修改可能影响多个切片,如果能限制容量和长度相等,则追加元素时一定会新建一个切片。

 

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/langs/990927.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-21
下一篇2022-05-21

发表评论

登录后才能评论

评论列表(0条)

    保存