第6篇:引用数据类型之切片

基础数据类型

  • 整型,用于表示整数
  • 浮点型,用于表示小数
  • 复数,用来表示复数
  • 布尔型,用于表示真/假
  • 字符串,用于表示文本信息

复合数据类型

  • 数组,用于表示多个数据(数据集合)
  • 结构体,用于自定义一些数据集合和方法

引用数据类型

  • 指针,用于表示内存地址的类型
  • 切片,用于表示多个数据(数据集合)
  • 字典,用于表示键值对集合
  • 函数,用于将一个语句序列打包为一个单元,然后可以从程序中其它地方多次调用
  • 通道,channel,是goroutine中的通信机制

接口数据类型

  • 接口,用于约束和泛指数据类型

一、切片的定义

Slice(切片)代表变长的序列,可以理解为动态数组,序列中每个元素都有相同的类型。一个slice类型一般写作[]T,其中T代表slice中元素的类型;slice的语法和数组很像,只是没有固定长度而已。

数组和slice之间有着紧密的联系。一个slice是一个轻量级的数据结构,提供了访问数组子序列(或者全部)元素的功能,而且slice的底层确实引用一个数组对象。切片(slice)是Go中重要的数据类型,每个切片对象内部都维护着:数组指针、切片长度、切片容量 三个数据,指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。内置的lencap函数分别返回slice的长度和容量。

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

在向切片中追加的数据个数大于容量时,内部会自动扩容且每次扩容都当前容量的2倍(当容量超过1024时每次扩容则只增加 1/4容量)。

需要说明,slice 并不是数组或数组指针。它通过内部指针和相关属性引用数组片段,以实现变长方案。

切片的特点如下:

  1. 切片:切片是数组的一个引用,因此切片是引用类型。但自身是结构体,值拷贝传递。
  2. 切片的长度可以改变,因此,切片是一个可变的数组。
  3. 切片遍历方式和数组一样,可以用len()求长度。表示可用元素数量,读写操作不能超过该限制。
  4. cap可以求出slice最大扩张容量,不能超出数组限制。0 <= len(slice) <= len(array),其中array是slice引用的数组。
  5. 切片的定义:var 变量名 []类型,比如 var str []stringvar arr []int
  6. 如果 slice == nil,那么 lencap 结果都等于 0。

二、创建切片

// 创建切片
var nums []int

// 创建切片
var data = []int{11,22,33}
data := []int{11,22,33}

// 创建切片
// make只用于 切片、字典、channel
var users = make([]int,1,3)
// 切片的指针类型
var v1 = new([]int)

// 指针类型(nil)
var v2 *[]int

示例

package main

import "fmt"

func main() {
    //1.声明切片
    var s1 []int
    // 2.:=
    s2 := []int{}
    // 3.make()
    var s3 = make([]int, 0)
    fmt.Println(s1, s2, s3) // [] [] []
    // 4.初始化赋值
    var s4 = make([]int, 0, 0)
    fmt.Println(s4) // []
    s5 := []int{1, 2, 3}
    fmt.Println(s5) // [1,2,3]
    // 5.从数组切片
    arr := [5]int{1, 2, 3, 4, 5}
    var s6 []int
    // 前包后不包
    s6 = arr[1:4]
    fmt.Println(s6) // [2,3,4]

    var s7 = new([]int)
    var s8 *[]int
    fmt.Println(s7, s8) // &[]  <nil>
}

三、切片初始化

1. 通过数组进行初始化

package main

import (
    "fmt"
)

var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[2:8]
var slice1 []int = arr[0:6]        //可以简写为 var slice []int = arr[:end]
var slice2 []int = arr[5:10]       //可以简写为 var slice[]int = arr[start:]
var slice3 []int = arr[0:len(arr)] //var slice []int = arr[:]
var slice4 = arr[:len(arr)-1]      //去掉切片的最后一个元素
func main() {
    fmt.Printf("全局变量:arr %v\n", arr)
    fmt.Printf("全局变量:slice0 %v\n", slice0)
    fmt.Printf("全局变量:slice1 %v\n", slice1)
    fmt.Printf("全局变量:slice2 %v\n", slice2)
    fmt.Printf("全局变量:slice3 %v\n", slice3)
    fmt.Printf("全局变量:slice4 %v\n", slice4)
    fmt.Printf("-----------------------------------\n")
    arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
    slice5 := arr[2:8]
    slice6 := arr[0:6]         //可以简写为 slice := arr[:end]
    slice7 := arr[5:10]        //可以简写为 slice := arr[start:]
    slice8 := arr[0:len(arr)]  //slice := arr[:]
    slice9 := arr[:len(arr)-1] //去掉切片的最后一个元素
    fmt.Printf("局部变量: arr2 %v\n", arr2)
    fmt.Printf("局部变量: slice5 %v\n", slice5)
    fmt.Printf("局部变量: slice6 %v\n", slice6)
    fmt.Printf("局部变量: slice7 %v\n", slice7)
    fmt.Printf("局部变量: slice8 %v\n", slice8)
    fmt.Printf("局部变量: slice9 %v\n", slice9)
}

输出结果:

全局变量:arr [0 1 2 3 4 5 6 7 8 9]
全局变量:slice0 [2 3 4 5 6 7]
全局变量:slice1 [0 1 2 3 4 5]
全局变量:slice2 [5 6 7 8 9]
全局变量:slice3 [0 1 2 3 4 5 6 7 8 9]
全局变量:slice4 [0 1 2 3 4 5 6 7 8]
-----------------------------------
局部变量: arr2 [9 8 7 6 5 4 3 2 1 0]
局部变量: slice5 [2 3 4 5 6 7]
局部变量: slice6 [0 1 2 3 4 5]
局部变量: slice7 [5 6 7 8 9]
局部变量: slice8 [0 1 2 3 4 5 6 7 8 9]
局部变量: slice9 [0 1 2 3 4 5 6 7 8]

2. 通过make来创建切片

var slice []type = make([]type, len)
slice  := make([]type, len)
slice  := make([]type, len, cap)

代码:

package main

import (
    "fmt"
)

var slice0 []int = make([]int, 10)
var slice1 = make([]int, 10)
var slice2 = make([]int, 10, 10)

func main() {
    fmt.Printf("make全局slice0 :%v\n", slice0)
    fmt.Printf("make全局slice1 :%v\n", slice1)
    fmt.Printf("make全局slice2 :%v\n", slice2)
    fmt.Println("--------------------------------------")
    slice3 := make([]int, 10)
    slice4 := make([]int, 10)
    slice5 := make([]int, 10, 10)
    fmt.Printf("make局部slice3 :%v\n", slice3)
    fmt.Printf("make局部slice4 :%v\n", slice4)
    fmt.Printf("make局部slice5 :%v\n", slice5)
}

输出结果:

    make全局slice0 :[0 0 0 0 0 0 0 0 0 0]
    make全局slice1 :[0 0 0 0 0 0 0 0 0 0]
    make全局slice2 :[0 0 0 0 0 0 0 0 0 0]
    --------------------------------------
    make局部slice3 :[0 0 0 0 0 0 0 0 0 0]
    make局部slice4 :[0 0 0 0 0 0 0 0 0 0]
    make局部slice5 :[0 0 0 0 0 0 0 0 0 0]

切片的内存布局

读写操作实际目标是底层数组,只需注意索引号的差别。

package main

import (
    "fmt"
)

func main() {
    data := [...]int{0, 1, 2, 3, 4, 5}

    s := data[2:4]
    s[0] += 100
    s[1] += 200

    fmt.Println(s)
    fmt.Println(data)
}

输出:

    [102 203]
    [0 1 102 203 4 5]

3. 直接创建 slice 对象,自动分配底层数组。

package main

import "fmt"

func main() {
    s1 := []int{0, 1, 2, 3, 8: 100} // 通过初始化表达式构造,可使用索引号。
    fmt.Println(s1, len(s1), cap(s1))

    s2 := make([]int, 6, 8) // 使用 make 创建,指定 len 和 cap 值。
    fmt.Println(s2, len(s2), cap(s2))

    s3 := make([]int, 6) // 省略 cap,相当于 cap = len。
    fmt.Println(s3, len(s3), cap(s3))
}

输出结果:

[0 1 2 3 0 0 0 0 100] 9 9
[0 0 0 0 0 0] 6 8
[0 0 0 0 0 0] 6 6

使用 make 动态创建slice,避免了数组必须用常量做长度的麻烦。还可用指针直接访问底层数组,退化成普通数组操作。

package main

import "fmt"

func main() {
    s := []int{0, 1, 2, 3}
    p := &s[2] // *int, 获取底层数组元素指针。
    *p += 100

    fmt.Println(s)
}

输出结果:

[0 1 102 3]

至于 [][]T,是指元素类型为 []T 。

package main

import (
    "fmt"
)

func main() {
    data := [][]int{
        []int{1, 2, 3},
        []int{100, 200},
        []int{11, 22, 33, 44},
    }
    fmt.Println(data)
}

输出结果:

[[1 2 3] [100 200] [11 22 33 44]]

四、修改底层数组

v1 := make([]int,1,3)

fmt.Println(len(v1),cap(v1))

// 其他
data := make([]int,3)

v1 := make([]int,1,3)

v2 := append(v1,66)

fmt.Println(v1)  // [0 ]
fmt.Println(v2)  // [0,66]

v1[0] = 999
fmt.Println(v1)  // [999 ]
fmt.Println(v2)  // [999,66]

// 需求:有一个切片,请往一个切片中追加一个数据。
v3 := make([]int,1,3)
v3 = append(v3,999)

v1 := []int{11,22,33}
v2 := append(v1,44)

v1[0] = 999

fmt.Println(v1) // [999 22 33]
fmt.Println(v2) // [11 22 33 44]

五、常见操作

1. 长度和容量

v1 := []int{11,22,33}
fmt.Println(len(v1), cap(v1))

2. 索引

v1 := []string{"kobe","乔丹","詹姆斯"}
v1[0]
v1[1]
v1[2]

v2 := make([]int,2,5)
v2[0]
v2[1]
v2[2]  // 报错


v2[0] = 999

3. 切片

v1 := []int{11,22,33,44,55,66}

v2 := v1[1:3]
v3 := v1[1:]
v4 := v1[:3]

// 注意:通过切片切出来的数据和原切片内部存储的数据地址相同

4. 追加

package main

import (
    "fmt"
)

func main() {
    v1 := []int{11,22,33}

    v2 := append(v1,44)

    v3 := append(v1,55,66,77,88)

    v4 := append(v1, []int{100,200,300}...)

    fmt.Println(v2)
    fmt.Println(v3)
    fmt.Println(v4)
}

>>> 输出
[11 22 33 44]
[11 22 33 55 66 77 88]
[11 22 33 100 200 300]

5. 删除

package main

import "fmt"

func main() {
    v1 := []int{11, 22, 33, 44, 55, 66}
    deleteIndex := 2

    // 切片获取到 {11,22,44、55、66}
    // 又获取到 {44, 55, 66},将44、55、66要追加到
    result := append(v1[:deleteIndex], v1[deleteIndex+1:]...)
    fmt.Println(result) // [11 22 44 55 66]
    fmt.Println(v1)     //[11 22 44 55 66 66]
}

注意:使用切片时不太会使用删除。【链表】

6. 插入

package main

import "fmt"

func main() {
    v1 := []int{11, 22, 33, 44, 55, 66}
    insertIndex := 3 // 在索引3的位置插入99

    result := make([]int, 0, len(v1)+1)
    result = append(result, v1[:insertIndex]...)
    result = append(result,99)
    result = append(result,v1[insertIndex:]...)
    fmt.Println(result)
}

注意:效率低下。【链表】

7. 循环

package main

import "fmt"

func main() {
    v1 := []int{11, 22, 33, 99, 55, 66}

    for i := 0; i < len(v1); i++ {
        fmt.Println(i, v1[i])
    }

    for index, value := range v1 {
        fmt.Println(index, value)
    }
}

8. 切片拷贝

package main

import (
    "fmt"
)

func main() {

    s1 := []int{1, 2, 3, 4, 5}
    fmt.Printf("slice s1 : %v\n", s1)
    s2 := make([]int, 10)
    fmt.Printf("slice s2 : %v\n", s2)
    copy(s2, s1)
    fmt.Printf("copied slice s1 : %v\n", s1)
    fmt.Printf("copied slice s2 : %v\n", s2)
    s3 := []int{1, 2, 3}
    fmt.Printf("slice s3 : %v\n", s3)
    s3 = append(s3, s2...)
    fmt.Printf("appended slice s3 : %v\n", s3)
    s3 = append(s3, 4, 5, 6)
    fmt.Printf("last slice s3 : %v\n", s3)

}

输出结果:

slice s1 : [1 2 3 4 5]
slice s2 : [0 0 0 0 0 0 0 0 0 0]
copied slice s1 : [1 2 3 4 5]
copied slice s2 : [1 2 3 4 5 0 0 0 0 0]
slice s3 : [1 2 3]
appended slice s3 : [1 2 3 1 2 3 4 5 0 0 0 0 0]
last slice s3 : [1 2 3 1 2 3 4 5 0 0 0 0 0 4 5 6]

copy :函数 copy 在两个 slice 间复制数据,复制长度以 len 小的为准。两个 slice 可指向同一底层数组,允许元素区间重叠。

package main

import (
    "fmt"
)

func main() {

    data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("array data : ", data)
    s1 := data[8:]
    s2 := data[:5]
    fmt.Printf("slice s1 : %v\n", s1)
    fmt.Printf("slice s2 : %v\n", s2)
    copy(s2, s1)
    fmt.Printf("copied slice s1 : %v\n", s1)
    fmt.Printf("copied slice s2 : %v\n", s2)
    fmt.Println("last array data : ", data)

}

输出结果:

array data :  [0 1 2 3 4 5 6 7 8 9]
slice s1 : [8 9]
slice s2 : [0 1 2 3 4]
copied slice s1 : [8 9]
copied slice s2 : [8 9 2 3 4]
last array data :  [8 9 2 3 4 5 6 7 8 9]

应及时将所需数据 copy 到较小的 slice,以便释放超大号底层数组内存。

9. 切片嵌套

package main

import "fmt"

func main() {
    v1 := []int{11, 22, 33, 99, 55, 66}
    v2 := [][]int{[]int{11, 22, 33, 44}, []int{44, 55}}
    v3 := [][2]int{[2]int{1, 2}, [2]int{4, 5}}

    fmt.Println(v1)
    fmt.Println(v2)
    fmt.Println(v3)

    v1[0] = 111111
    v2[0][2] = 222222
    v3[1][0] = 99999

    fmt.Println(v1)
    fmt.Println(v2)
    fmt.Println(v3)
}

六、数组和切片的内存布局

数组和切片内存布局

1. 字符串和切片(string and slice)

string底层就是一个byte的数组,因此,也可以进行切片操作。

package main

import (
    "fmt"
)

func main() {
    str := "hello world"
    s1 := str[0:5]
    fmt.Println(s1)

    s2 := str[6:]
    fmt.Println(s2)
}

输出结果:

    hello
    world

string本身是不可变的,因此要改变string中字符。需要如下操作: 英文字符串:

package main

import (
    "fmt"
)

func main() {
    str := "Hello world"
    s := []byte(str) //中文字符需要用[]rune(str)
    s[6] = 'G'
    s = s[:8]
    s = append(s, '!')
    str = string(s)
    fmt.Println(str)
}

输出结果:

    Hello Go!

2. 含有中文字符串:

package main

import (
    "fmt"
)

func main() {
    str := "你好,世界!hello world!"
    s := []rune(str) 
    s[3] = '够'
    s[4] = '浪'
    s[12] = 'g'
    s = s[:14]
    str = string(s)
    fmt.Println(str)
}

输出结果:

你好,够浪!hello go

golang slice data[:6:8] 两个冒号的理解

常规slice , data[6:8],从第6位到第8位(返回6, 7),长度len为2, 最大可扩充长度cap为4(6-9)

另一种写法: data[:6:8] 每个数字前都有个冒号, slice内容为data从0到第6位,长度len为6,最大扩充项cap设置为8

a[x:y:z] 切片内容 [x:y] 切片长度: y-x 切片容量:z-x

package main

import (
    "fmt"
)

func main() {
    slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    d1 := slice[6:8]
    fmt.Println(d1, len(d1), cap(d1))
    d2 := slice[:6:8]
    fmt.Println(d2, len(d2), cap(d2))
}

数组or切片转字符串:

strings.Replace(strings.Trim(fmt.Sprint(array_or_slice), "[]"), " ", ",", -1)

七、动态扩容

1. 超出原 slice.cap 限制,就会重新分配底层数组,即便原数组并未填满。

package main

import (
    "fmt"
)

func main() {

    data := [...]int{0, 1, 2, 3, 4, 10: 0}
    s := data[:2:3]

    s = append(s, 100, 200) // 一次 append 两个值,超出 s.cap 限制。

    fmt.Println(s, data)         // 重新分配底层数组,与原数组无关。
    fmt.Println(&s[0], &data[0]) // 比对底层数组起始指针。

}

输出结果:

[0 1 100 200] [0 1 2 3 4 0 0 0 0 0 0]
    0xc4200160f0 0xc420070060

从输出结果可以看出,append 后的 s 重新分配了底层数组,并复制数据。如果只追加一个值,则不会超过 s.cap 限制,也就不会重新分配。 通常以 2 倍容量重新分配底层数组。在大批量添加数据时,建议一次性分配足够大的空间,以减少内存分配和数据复制开销。或初始化足够长的 len 属性,改用索引号进行操作。及时释放不再使用的 slice 对象,避免持有过期数组,造成 GC 无法回收。

2. slice中cap重新分配规律

package main

import (
    "fmt"
)

func main() {
    s := make([]int, 0, 1)
    c := cap(s)
    for i := 0; i < 50; i++ {
        s = append(s, i)
        if n := cap(s); n > c {
            fmt.Printf("cap: %d -> %d\n", c, n)
            c = n
        }
    }
}

输出结果:

cap: 1 -> 2
cap: 2 -> 4
cap: 4 -> 8
cap: 8 -> 16
cap: 16 -> 32
cap: 32 -> 64
cap: 64 -> 128
cap: 128 -> 256
cap: 256 -> 512
cap: 512 -> 1024
cap: 1024 -> 1280
cap: 1280 -> 1696
cap: 1696 -> 2304

如果切片的容量小于 1024 个元素,于是扩容的时候就翻倍增加容量。上面那个例子也验证了这一情况,总容量从原来的4个翻倍到现在的8个。一旦元素个数超过 1024 个元素,那么增长因子就变成 1.25 ,即每次增加原来容量的四分之一。

注意:扩容扩大的容量都是针对原来的容量而言的,而不是针对原来数组的长度而言的。

八、变量赋值

  • 整型

    package main
    
    import "fmt"
    
    func main() {
        v1 := 1
        v2 := v1
    
        fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000b4008
        fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000b4010
    }
  • 布尔类型

    package main
    
    import "fmt"
    
    func main() {
        v1 := false
        v2 := v1
    
        fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc00012a002
        fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc00012a003
    }
  • 浮点型

    package main
    
    import "fmt"
    
    func main() {
        v1 := 3.14
        v2 := v1
    
        fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc000016050
        fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc000016058
    }
  • 字符串

    package main
    
    import "fmt"
    
    func main() {
        v1 := "张亚飞"
        v2 := v1
    
        fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc000010200
        fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc000010210 
    }

    注意:字符串内部元素不可被修改。

  • 数组

    package main
    
    import "fmt"
    
    func main() {
        v1 := [2]int{6, 9}
        v2 := v1
        fmt.Println(v1, v2)
        fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000b4010
        fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000b4020
    
        v1[0] = 11111
        fmt.Println(v1, v2)
    }
  • 切片

    package main
    
    import "fmt"
    
    func main() {
        v1 := []int{6, 9}
        v2 := v1
        fmt.Println(v1, v2)              // [6 9] [6 9]
        fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000a6020
        fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000a6040
    
        v1[0] = 11111
        fmt.Println(v1, v2) // [11111 9] [11111 9]
    }

    如果扩容,那么内部存储数据的数组就会重新开辟区域。

    package main
    
    import "fmt"
    
    func main() {
        v1 := []int{6, 9}
        v2 := v1
        fmt.Println(v1, v2)              // [6 9] [6 9]
        fmt.Printf("v1的内存地址:%p \n", &v1) // 0xc0000a6020
        fmt.Printf("v2的内存地址:%p \n", &v2) // 0xc0000a6040
    
        v1 = append(v1, 999)
        fmt.Println(v1, v2) // [11111 9] [11111 9]
    }

总结,目前所学的所有的数据类型中,在修改切片的内部元素时,会造成所有的赋值的变量同时修改(不扩容)。

扩展:引用类型和值类型

九、练习题

  1. 简述切片和数组的区别?

    ● 切片是指针类型,数组是值类型

    ● 数组的长度是固定的,而切片不是(切片是动态的数组)

    ● 切片比数组多一个属性:容量(cap)

    ● 切片的底层是数组

  2. 简述new和make的区别?

    • 二者都是用来做内存分配的。
    • make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
    • 而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。
  3. 看代码写结果

    v1 := make([]int,2,5)
    fmt.Println(v1[0],len(v1),cap(v1))
  4. 看代码写结果

    v1 := make([]int,2,5)
    v2 := append(v1,123)
    
    fmt.Println(len(v1),cap(v1)) // 2,5
    fmt.Println(len(v2),cap(v2)) // 3,5
    fmt.Println(v1) // [0 0]
    fmt.Println(v2) // [0 0 123]

  5. 看代码写结果

    v1 := make([]int,2,5)
    v2 := append(v1,123)
    v1[0] = 999
    
    fmt.Println(v1) // [999 0]
    fmt.Println(v2) // [999, 0, 123]
  6. 看代码写结果

    v1 := make([]int,2,2)
    v2 := append(v1,123)
    v1[0] = 999
    
    fmt.Println(v1) // [999 0]
    fmt.Println(v2) // [0 0 123]

  7. 看代码写结果

    v1 := make([]int,2,2)
    v2 := v1[0:2]
    
    v1[0] = 111
    
    fmt.Println(v1) // [111,0]
    fmt.Println(v2) // [111,0]
  8. 看代码写结果

    v1 := [][]int{ []int{11, 22, 33, 44},  []int{44, 55} }
    v1[0][2] = 999
    fmt.Println(v1) // [ [11 22 99 44]  [44,55] ]
  9. 看代码写结果

    v1 := [][]int{[]int{11, 22, 33, 44}, []int{44, 55}}
    v2 := v1[0]
    
    v2[2] = 69
    fmt.Println(v1)  // [[11 22 69 44] [44 55]]
  10. 看代码写结果

    v1 := [][]int{[]int{11, 22, 33, 44}, []int{44, 55}}
    v2 := append(v1[0],99)
    
    v2[2] = 69
    fmt.Println(v1) // [[11 22 33 44] [44 55]]
  11. 看代码写结果

    v1 := [][]int{ make([]int, 2, 5), make([]int, 2, 3) }
    v2 := append(v1[0], 99)
    
    fmt.Println(v1) // [ [0 0], [0 0 ] ]
    fmt.Println(v2) // [0 0 99]
    
    v2[0] = 69
    fmt.Println(v1) // [ [69 0], [0 0 ] ]
    fmt.Println(v2) // [69 0 99]

文章作者: 张亚飞
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 张亚飞 !
评论
 上一篇
第28篇:迭代器和生成器 第28篇:迭代器和生成器
学习目标:把可迭代对象、迭代器和生成器的概念和用法掌握 在了解Python的数据结构时,容器(container)、可迭代对象(iterable)、迭代器(iterator)、生成器(generator)、列表/集合/字典推导式(list,
2020-12-27
下一篇 
第5篇:复合数据类型之数组 第5篇:复合数据类型之数组
数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。因为数组的长度是固定的,因此在Go语言中很少直接使用数组。和数组对应的类型是Slice(切片),它是可以增长和收缩的动态序列,slice功能也更灵活,但是要理解slice工作原理的话需要先理解数组。
2020-12-27
  目录