具有slice参数的功能将不会修改原始容量

问题描述 投票:-1回答:2

为什么在去编辑函数内部的切片时不应用长度更新?

快速响应:因为切片仅是对原始数组的引用

如您在以下示例中看到的,我有一个切片,它将由外部函数在值中进行修改,但是直到您从函数返回值并将其重新分配给原始切片之前,追加操作将被完全忽略。

为了改进示例,我添加了通过引用传递的功能并进行了修改操作以提高解决方案的舒适度

package main

import (
    "fmt"

)
var sli = make([]int,8)

func main() {

    fmt.Println("START STATUS_____")
    fmt.Println("slice",sli)
    fmt.Println("   cap:", cap(sli))
    fmt.Println("   len:", len(sli))

    editSli(sli)
    fmt.Println("EDIT RESULT STATUS_____")
    fmt.Println("slice",sli)
    fmt.Println("   cap:", cap(sli))
    fmt.Println("   len:", len(sli))


    sli = updateSli(sli)
    fmt.Println("UPDATE RESULT STATUS_____")
    fmt.Println("slice",sli)
    fmt.Println("   cap:", cap(sli))
    fmt.Println("   len:", len(sli))

    sli = append(sli, 15, 16, 17)
    fmt.Println("DIRECT APPEND RESULT STATUS_____")
    fmt.Println("slice",sli)
    fmt.Println("   cap:", cap(sli))
    fmt.Println("   len:", len(sli))

    sli[13] = 99
    fmt.Println("DIRECT ASSIGNMENT OF LAST ELEMENT (13°) STATUS_____")
    fmt.Println("slice",sli)
    fmt.Println("   cap:", cap(sli))
    fmt.Println("   len:", len(sli))

    updateSliPointer(&sli)
    fmt.Println("\n*** Finally, passing the slice as a pointer will modify the sctructure: ")
    fmt.Println("slice",sli)
    fmt.Println("   cap:", cap(sli))
    fmt.Println("   len:", len(sli))
}

func editSli(sliOrigin []int) {
    sliOrigin[7] = 11
    sliOrigin = append(sliOrigin, 33, 34, 35) //don't work
    fmt.Println("\ninside the edit Slice function the sli is =", sliOrigin)
    fmt.Println("and the direct assignment of the last element (7°) ar right working.")
    fmt.Println("However, the slice append will not be applied to the original slice because this is an internal copy")
}

func updateSli(sliOrigin []int) []int{
    sliOrigin = append(sliOrigin, 12, 13, 14) //it works!
    fmt.Println("\ninside the update Slice function the sli is = ", sliOrigin)
    fmt.Println("and this append will be applied to the original one becouse of the return value of this function is a new slice")
    return sliOrigin
}

func updateSliPointer(sliOrigin *[]int) {
    //don't work *sliOrigin[7] = 11
    *sliOrigin = append(*sliOrigin, 100, 101, 102)
    fmt.Println("\ninside the UPDATE Slice POINTER function we have a sli pointer and we can modify directly the structures appending elements =", sliOrigin)
    fmt.Println("\nbut to access the values and modify it we have to create a local instance")
    var x = *sliOrigin
    x[4] = 9
}

运行此操作将产生:

START STATUS_____
slice [0 0 0 0 0 0 0 0]
    cap: 8
    len: 8

inside the edit Slice function the sli is = [0 0 0 0 0 0 0 11 33 34 35]
and the direct assignment of the last element (7°) ar right working.

However, the slice append will not be applied to the original slice because this is an internal copy
EDIT RESULT STATUS_____
    slice [0 0 0 0 0 0 0 11]
    cap: 8
    len: 8

inside the update Slice function the sli is =  [0 0 0 0 0 0 0 11 12 13 14]
and this append will be applied to the original one becouse of the return value of this function is a         new slice
UPDATE RESULT STATUS_____
    slice [0 0 0 0 0 0 0 11 12 13 14]
    cap: 16
    len: 11
DIRECT APPEND RESULT STATUS_____
    slice [0 0 0 0 0 0 0 11 12 13 14 15 16 17]
    cap: 16
    len: 14
DIRECT ASSIGNMENT OF LAST ELEMENT (13°) STATUS_____
    slice [0 0 0 0 0 0 0 11 12 13 14 15 16 99]
    cap: 16
    len: 14

inside the UPDATE Slice POINTER function we have a sli pointer and we can modify directly the         structures appending elements = &[0 0 0 0 0 0 0 11 12 13 14 15 16 99 100 101 102]

but to access the values and modify it we have to create a local instance

*** Finally, passing the slice as a pointer will modify the sctructure: 
    slice [0 0 0 0 9 0 0 11 12 13 14 15 16 99 100 101 102]
    cap: 32
    len: 17
function go append return-value slice
2个回答
7
投票

您从根本上误解了什么是切片。切片是具有3个字段的结构:指向基础数组的指针,数据的长度和基础数组的容量(相对于指针)。当您将切片传递给函数时,就是在对该结构进行copy。它仍然引用基础数组,因此您对实际data所做的更改将反映在函数范围之外,但会获得对切片标题本身(包括数据长度)的更改不是,因为它是copy。如果您需要修改切片而不是基础数据,并将其反映在函数外部,请传递指向切片的指针!

推荐阅读:https://blog.golang.org/go-slices-usage-and-internals


3
投票

editSli不起作用,因为您要更改切片的本地副本的容量而不返回它。基本上,您的函数必须出于[[完全相同的原因返回新切片,而append必须返回更新的切片。因为如果必须增加容量,则可能必须使用新的基础数组,因此对该切片的任何旧引用将无效。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.