美文网首页Go
Go陷阱之切片扩容

Go陷阱之切片扩容

作者: Dakini_Wind | 来源:发表于2021-04-20 10:57 被阅读0次

    go语言的切片实在是好用,但如果不了解它的坑,代码分分钟变为火葬场。
    这里记录一下切片扩容所可能犯的错误。

    1. 函数中的切片扩容

    func Append(nums []int, a int) {
        nums = append(nums, a)
    }
    
    func main() {
        nums := []int{1, 2, 3}
        Append(nums, 4)
        fmt.Println(nums)
    }
    

    output:

    [1 2 3]
    

    解析:

    当切片存储容量不足时,则会把当前切片进行扩容并产生新的切片。新的切片具有新的地址,但是go是按值传递,所以新的切片地址只是局部变量,是不能够随着函数返回的。
    若切片容量足够,切片作为函数传参扩容后返回的还是原来的切片内容。因为决定切片的还有len

    其他:

    func Set(nums []int) {
        nums[0] = 999
    }
    
    func main() {
        nums := make([]int, 3, 4)
        nums[2] = 2
        Set(nums)
        fmt.Println(nums)
    }
    

    output:

    [999 0 2]
    

    解析:

    切片作为参数传递时,传递的本质还是指向实际存储的数组的地址,所以还是能够改变值的。只是在进行append操作时需要注意。

    2. append后赋值给匿名变量

    func main() {
        nums := []int{1, 2, 3}
        _ = append(nums, 4)
        fmt.Println(nums)
    }
    

    output:

    [1 2 3]
    

    解析:

    append产生一个新切片,但是因为赋值给了匿名变量,所以不会影响原变量。

    3. 空切片

    func main() {
       var errs []error
       errs = append(errs, nil)
       fmt.Println(errs)
    }
    

    output:

    [<nil>]
    

    解析:

    nil也是一个值,可以对数组进行追加。需要注意的是实际使用时可能存在风险。

    4. 对同一个数组进行多次append操作

    dfs相关算法中会经常进行这种操作,需要额外注意。

    func main() {
        x := make([]int, 0, 10)
        x = append(x, 1, 2, 3)
        y := append(x, 4)
        z := append(x,5)
        fmt.Println(x)
        fmt.Println(y)
        fmt.Println(z)
    }
    

    output:

    [1 2 3]
    [1 2 3 5]
    [1 2 3 5]
    

    解析:

    数组xcap为10,在进行append操作后,len变为3。
    再在x上进行 append 4 赋值给y,此时因为xcap大于4,所以不需要进行扩容,会在x的基础上进行追加。即xy实际用于存储的数组指向同一块内存。
    此时 y为[1 2 3 4],但此时x为[1 2 3],因为决定切片的还有len,尽管内存中实际存储的还有4。
    再在x上进行 append 5 赋值给zx这块内存数组的第4位将存为5,覆盖原来的4(因为xlen为3,append的为第4位)。
    这时候x依然受len影响不会变,z变为[1 2 3 5]。此时,xyz实际进行存储的数组指向了同一块内存。所以z进行append时会影响y,此时y也为[1 2 3 5]。

    相关文章

      网友评论

        本文标题:Go陷阱之切片扩容

        本文链接:https://www.haomeiwen.com/subject/jrpwlltx.html