领先的免费Web技术教程,涵盖HTML到ASP.NET

网站首页 > 知识剖析 正文

golang 数组和slice的区别 go slice 数组

nixiaole 2024-11-10 12:31:23 知识剖析 16 ℃

数组和slice的区别

1.使用方式

数组和slice操作方式差不多, 并且slice包含了数组的基本的操作方式, 如下标、range循环, 还有一些如len()则是多种类型共用,

数组的声明方式很单一,通常这样:

array1 := [6]int{1, 2, 3, 4, 5,6}
array2 := [...]int{1, 2, 3, 4, 5,6}
array3 := [6]int{}

slice的声明方式就非常多样了, 如前面介绍的几种:

var slice1 = []int{1, 2, 3, 4, 5,6}
var slice2 = make([]int, 0, 6)
var slice3 = make([]int, 5, 6)
var slice4 = make([]int, 5)

加上对数组的切片和append操作都会产生数组切片(slice)

数组的创建方式

一维数组

package main
import (
    "fmt"
)
    //全局
    var arr0 [5]int = [5]int{1, 2, 3}
    var arr1 = [5]int{1, 2, 3, 4, 5}
    var arr2 = [...]int{1, 2, 3, 4, 5, 6}
    var str = [5]string{3: "hello world", 4: "tom"}
func main() {
    //局部
    a := [3]int{1, 2} // 未初始化元素值为 0。
    b := [...]int{1, 2, 3, 4} // 通过初始化值确定数组长度。
    c := [5]int{2: 100, 4: 200} // 使用引号初始化元素。
    d := [...]struct {
    name string
    age uint8
    }{
    {"user1", 10}, // 可省略元素类型。
    {"user2", 20}, // 别忘了最后一行的逗号。
    }
    fmt.Println(arr0, arr1, arr2, str)
    fmt.Println(a, b, c, d)
}

二维数组

package main
import (
    "fmt"
)
    //全局
    var arr0 [5][3]int
    var arr1 [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
func main() {
    //局部
    a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    b := [...][2]int{{1, 1}, {2, 2}, {3, 3}} // 第 2 纬度不能用 "..."。
    fmt.Println(arr0, arr1)
    fmt.Println(a, b)
}

切片的创建方式

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

全局:

var arr = [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
var slice0 []int = arr[start:end]
var slice1 []int = arr[:end]
var slice2 []int = arr[start:]
var slice3 []int = arr[:]
var slice4 = arr[:len(arr)-1] //去掉切片的最后一个元素

局部:

arr2 := [...]int{9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
slice5 := arr[start:end]
slice6 := arr[:end]
slice7 := arr[start:]
slice8 := arr[:]
slice9 := arr[:len(arr)-1] //去掉切片的最后一个元素

2.值传递or引用传递

package main
import (
		"fmt"
)
//值拷贝行为会造成性能问题, 通常会建议使用 slice, 或数组指针。
func arrayModify(array [5]int) {
    newArray := array
    newArray[0] = 88
}
func sliceModify(slice []int) {
    newSlice := slice
    newSlice[0] = 88
}
func main() {
    array := [5]int{1, 2, 3, 4, 5}
    slice := []int{1, 2, 3, 4, 5}
    arrayModify(array)
    sliceModify(slice)
    fmt.Println(array)
    fmt.Println(slice)
}

输出

[1 2 3 4 5]

[88 2 3 4 5]

实例: 切片和数组之间的拷贝: 拷贝切片

package main
import (
    "fmt"
    "reflect"
)
func main() {
    s := []int{1, 2, 3} //切片的定义方法
    var a [3]int //数组的定义方法
    var b [3]int //数组的定义方法
    //fmt.Println(copy(a, s)) //Error: first argument to copy should be slice; have [3]int
    //copy函数第一个参数(目标)只能接收切片参数,我们可以使用[:]方式将数组转换成切片
    fmt.Println(s[:2]) //[1 2]
    fmt.Println(copy(a[:2], s)) //2 部分拷贝 a[:2] 目标 s 原数组
    fmt.Println(a) //[1, 2, 0]
    fmt.Println(copy(b[:], s)) //3 全部拷贝 b[:] 目标 s 原数组
    fmt.Println(b) //[1, 2, 3]
    fmt.Println(reflect.TypeOf(a), reflect.TypeOf(b)) //[3]int [3]int
}

显示的结果

D:\work\src>go run test.go

2

[1 2 0]

3

[1 2 3]

实例: 切片和数组之间的拷贝: 拷贝数组

package main
import (
    "fmt"
    "reflect"
)
func main() {
    a := [...]int{1, 2, 3} //数组的定义方法
    s := make([]int, 3) //切片的定义方法
    fmt.Println(copy(s, a[:2])) //2 拷贝的数量 s 为目标(参数必须为切片类型) a 为 源 a[:2] 省略low, high, 取长度, :2 代表从开始位置取两个元素
    fmt.Println(s) // [1 2 0]
    fmt.Println(reflect.TypeOf(a), reflect.TypeOf(s)) //[3]int []int
}

array 与 slice 之间转换

array 转换成 slice (array => slice)

实例1: array => slice 第一种方法

package main
import (
    "fmt"
    "reflect"
)
func main() {
    s := [3]int{1, 2, 3}
    var a []int
    var b []int
    a = s[:] //获取全部
    b = s[0:2] //获取部分
    fmt.Println(a, b) //[1 2 3] [1 2]
    fmt.Println(reflect.TypeOf(a), reflect.TypeOf(b)) //[]int []int
}

实例2: array => slice 第二种方法

package main
import (
    "fmt"
    "reflect"
)
func main() {
    s := [3]int{1, 2, 3}
    //var a []int 虽然切片可以这样定义, 但是此种定义方法 导致for遍历时会出现错误
    var a = make([]int, 3) //切片的定义方法
    for index, item := range s {
    a[index] = item
    }
    fmt.Println(a, reflect.TypeOf(a)) //[1 2 3] []int
}

slice 转换成 array (slice => array)

实例1:

package main
import (
    "fmt"
    "reflect"
)
func main() {
    var arr [3]int //定义数组
    s := []int{1, 2, 3} //切片的定义方法
    copy(arr[:], s[:]) //copy(dst, src)
    fmt.Println(arr, reflect.TypeOf(arr)) //[1 2 3] [3]int
}

实例2:

package main
import (
    "fmt"
    "github.com/google/uuid"
)
func main() {
    //注意: [16]byte 和 []byte 是不同类型 不能直接赋值
    var id uuid.UUID //[16]byte
    if id[0] == 0 { //判断是否为空的方法
    		fmt.Println("值为空", len(id), id[0])
    }
    id = uuid.New()
    fmt.Println(id)
    uniqueId := uuid.New()
    fmt.Println(uniqueId)
    // [16]byte => []byte 转换的方法
    //方法一
    var id2 []byte
    id2 = uniqueId[:] // [16]byte => []byte 转换的方法
    fmt.Println(id2)
    //方法二
    var id3 []byte
    id3, err := uniqueId.MarshalBinary() // [16]byte => []byte 转换的方法 期本质就是 [:] 封装的方法
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(id3)
    // []byte 转换成 [16]byte
    id, err = uuid.FromBytes(id3) // // []byte => [16]byte copy(uuid[:], id3[:]) copy(dst, src)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(id)
}

Tags:

最近发表
标签列表