带参数的golang函数不会修改原始容量

时间:2018-01-26 15:34:13

标签: function go append return-value slice

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

  

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

正如您在下面的示例中所看到的,我有一个切片,将通过外部函数在值中修改,但是在您从函数返回值并将其重新分配给原始切片之前,将完全忽略追加操作

  

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

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

2 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:3)

public function testData() { $data = 10; // Test using $data return $data; } /** * @depends testData */ public function testSameData($data) { // More tests using data } 无法正常工作,因为您正在更改切片本地副本的容量而不返回切片。基本上,您的函数必须为完全相同的原因返回新切片 editSli必须返回更新的切片;因为如果它必须增加容量,它可能必须使用新的底层数组,因此对切片的任何旧引用都将无效。