Day6 Array and Slice

前言

在GO当中,有两种资料结构是能够储存多项相同型态资料的,分别为ArraySlice

  • Array: List的长度是固定的,处於原生型别,对开发者来说使用次数较少。
  • Slice: List的长度为不固定,使用[]来进行定义,像是[]int 就是int slice,指的是slice里头的元素皆为int。

无论是Array或是Slice,皆必须指定里头资料的型别,且里头资料的型别必须一致。

阵列 Array

阵列的长度在宣告後无法改变,若在某些index未赋予值,则该index值为此type的预设值,像是int的预设值就是0

package main

import "fmt"

func main() {
	var a [5]int
	a[0] = 10
	a[1] = 100
	a[2] = 1000
	fmt.Println(a)
}

运算可得结果

[10 100 1000 0 0]

此外

  • 值也可以一开始就给,可部分宣告值,没值的预设为零值
  • Array可以只选用其中的某段资料
  • 可以利用[...]来让系统设定array长度
package main

import "fmt"

func main() {
	b := [5]int{1, 10, 100}
	fmt.Println(b)
	
	c := [5]int{2, 20, 200, 2000}
	fmt.Println(c[1:3])
	
	d := [...]int{3, 30, 300, 3000}
	fmt.Println(d)
}

运算後可得结果

[1 10 100 0 0]
[20 200]
[3 30 300 3000]
4

array 地雷

e:= []int{1,2}

[]当中没有任何东西的宣告是属於Slice,而不是省略长度的ArrayArray一定需要赋予长度!

切片 Slice

An array has a fixed size.
A slice, on the other hand, is a dynamically-sized,
flexible view into the elements of an array.

Slice可以视为长度不固定的Array

宣告时中括号[]里为空

Slice拆开来看,这玩意包含了三样东西:

  • 长度len,指的是现在的长度
  • 容量cap,指的是最大能容纳的长度
  • 指针ptr,透过指针,我们能与别人共用同个地方

建立slice

以下为几种宣告Slice的方式

package main
import (
    "fmt"
)
func main() {
    a := make([]int, 2)
    fmt.Println(a, len(a), cap(a), len(a) == 0, a == nil)

    b := make([]int, 2, 4)
    fmt.Println(b, len(b), cap(b), len(b) == 0, b == nil)

    var c = []int{} 
    fmt.Println(c, len(c), cap(c), len(c) == 0, c == nil)

    var d []int 
    fmt.Println(d, len(d), cap(d), len(d) == 0, d == nil)

    e := []string{"ironman", "2021"}
    fmt.Println(e, len(e), cap(e), len(e) == 0, e == nil)
}

运算後得到结果

[0 0] 2 2 false false
[0 0] 2 4 false false
[] 0 0 true false
[] 0 0 true true
[ironman 2021] 2 2 false false
  • a: 设定len为2,没给容量。但因最大容量长度不可能小於2,故系统设定为2
  • b: 设定len为2,容量为4。
  • c: 初始化的slice
  • d: 尚未初始化的slice,此时等同於nil
  • e: 直接赋予值的slice

slice深层解析

Slice并不是真正存值,而是透过指针指到更下面的地方,记忆体中的某个阵列

这也是为什麽说可以跟别人共用的原因。

如果SliceA跟SliceB都是一样的值,底层阵列只要储存一份资料,这样也能节省记忆体空间。
https://ithelp.ithome.com.tw/upload/images/20210921/20129737321DN2ETdW.png

package main

import "fmt"

func main() {
	a := make([]int, 0, 10) 
	b := append(a, 1, 2, 3)
	_ = append(a, 99, 88, 77)
	fmt.Println(b)

	aa := make([]int, 0, 2)
	bb := append(aa, 1, 2, 3)
	_ = append(aa, 99, 88, 77)
	fmt.Println(bb)

}

运行後可得

[99 88 77]
[1 2 3]

足够容量中没发生灾情,但是在超小容量中却因为後来的_做了append

导致我的aa中的值也被改了?

没错,这就是可以看到pointer的地方,原因在於底层的阵列被後来的_盖掉了。

Summary

这一次所介绍的ArraySlice就类型与用途来说就完全与Python的List或是Tuple完全不同了,这边就会需要读者适应一下,无论是固定类型长度,或者是使用规则方面,但这样的学习与使用方式,也会让我们更了解这两种资料结构的底层运作逻辑。


<<:  Day6-网站阅读进度条(上)_到底哪里少算了

>>:  软件开发後的成效追踪方式

Day [0] — JS之浸猪笼系列

大家好,打给安安,我是六角学院火箭队6th前端组的小废物POKA 看我的ID就知道我是来吃午餐ㄉ!?...

Day22 AWS - SignUp & MFA

先前开发的功能都是只有在本机执行,顶多同一个区域网路的用户可以使用服务,还是得想个办法让其他外网用户...

【Day16】:Counter的硬体实现

今天的内容主要是让大家知道,究竟counter是如何透过硬体来实作出来的,牵涉到数位逻辑设计相关内容...

Dungeon Mizarka 023

这几天可能不会有什麽进展,今天先将之前试验建置VS的部份做个整理。整理有关於Code strippi...

线性串列的链式储存 - DAY 5

前言 资料结构由逻辑和储存结构组成,了解他们不难,难的是你想解决的问题,问题牵涉到的的现实事物,可以...