believes that this topic may be considered as a commonplace menstrual topic. For a long time, a "value transfer" can basically understand all kinds of situations, but recently encountered a deeper "small pit" to share with you.

is the first starting from the most simple, see the following code:

 func (main) {a = []int{7,8,9}: fmt.Printf ("len:%d cap:%d data:%+vn", len (a), cap (a), a) AP (a) fmt.Printf ("len:%d cap:%d data:%+vn", len (a). Cap (a), a func (a []int AP)}) {a = append (a, 10) what is the output of the}

code above?

I'm not guessing here directly, and then call the AP function of append after the operation, a is still []int{7,8,9}. The reason is simple. No reference transfer in Go is all value transfer. Value transfer means that the transfer is a copy of the data. This sentence beginners may be slightly foggy, but the actual situation is strange, for example, the following code:

 func (main) {a = []int{7,8,9}: fmt.Printf ("len:%d cap:%d data:%+vn", len (a), cap (a), a AP (a) fmt.Printf (len:%d cap:%d) "data:%+vn, len (a), cap (a), a func AP (a)} []int {a[0] = 1) a = append (a, 10)}

and AP A after the output, you will see a[0] to 1, but a cap is still 3, 10 looks and is not append go?

looks more unthinkable, isn't it a value transfer, why is it still affecting the value of an external variable? Arguably either variable or constant decorous.

this is not really fantastic, because Go and C are not the same, slice looks like an array, is actually a structure, data structure of the source is:

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

this structure is also very good understanding, array is a true the array pointer, pointing to a continuous memory space in the head, len and cap represent the length and capacity.
in other words, you seem to pass parameters in the code written is ap (a []int), in fact in the code compilation, this code into ap (a runtime.slice
) so you can try to understand, AP (a) to replace ap (array: 0x123, len: 3, cap: 3) . It is obvious to see that the three parameters passed to the AP function are only 3 values, and no reference relationship is established with the external variable a. This is the value transfer.

, however, you might be wondering, why did I change the value of the a[0], and do it in the outside? In fact, you can see here should have they want to understand, because array is an address value (such as 0x123), the incoming address of the AP function, but it represents the address of 0x123 and external a 0x123 is a memory address, you modify the a[0], modify the value of 0x123 is actually stored in the address, so of course, will be affected by the external.

take an example of image. Suppose you are a railway station's cargo manager. You manage first to third cars. One day when you are sick, find someone (called A) to take a temporary hand. But the train is not what you want to touch. You have to prove it. So you copy the original copy of your hand to A and give A the key to the first car. Because just a few days are more busy, the stationmaster also let A also be responsible for the fourth carriage, so A also got the proof original of the car 4. After a period of time, you still get 1 to 3 cars' certificates after you get sick. You can see that A has done things in 1 to 3 carriages recently, but you are not qualified to go to 4 compartment. The examples above

should be very good at explaining the scene of slice passing the reference. Remember, only the value transfer in Go. Is

going to be done? But it's not so simple. I've been working on this problem recently. 按照上面的举例,虽然你没有资格去查看4车厢,但是如果你好奇,你可以偷看啊,因为它们是连续的互通的,正如数组也是一段连续的内存,于是就有这样的代码:

 func main() {   a := []int{}   a = append(a, 7,8,9)   fmt.Printf("len: %d cap:%d data:%+vn", len(a), cap(a), a)   ap(a)   fmt.Printf("len: %d cap:%d data:%+vn", len(a), cap(a), a)   p := unsafe.Pointer(&a[2])   q := uintptr(p)+8   t := (*int)(unsafe.Pointer(q))   fmt.Println(*t) }  func ap(a []int) {   a = append(a, 10) }

虽然外部的cap和len并没有改变,但是ap函数往同一段内存地址append了一个10,那我是不是可以用比较trick的方法去偷看呢? For example, find the address of a[2], and the length of a int should be 10 of the new AP function. It is important to note that the server of the Go official network is 32 bits, so int is 4 bytes when the code is executed by go playground.

executes the same result as I expected!

 func main but followed () {A: []int{7,8,9} = fmt.Printf ("len:%d cap:%d data:%+vn", len (a), cap (a), a) AP (a) fmt.Printf ("len:%d cap:%d data:%+vn", len (a), cap (a), a): P unsafe.Pointer = (& a[2]): q = uintptr (P): T = +8 (*int) (unsafe.Pointer (q)) fmt.Println (*t)} func AP (a []int) {a = append (a, 10)}

and the above is an example of the only difference is that slice is the beginning of initialization []int{7,8,9} this way. The execution result *t is 3 rather than 10, which is perplexed. Why? Isn't it a continuous memory space? The problem of

is actually the growth problem of slice. When append is found, cap is not enough, it will redistribute the space. The specific source code can be seen in growslice function in runtime/slice.go. I don't speak too much of the details here, only the results. When growslice occurs, a larger memory is reassigned to the slice, then the original data copy is past, and the array pointer of the slice is directed to the new memory. That is to say, if the previous data is stored into the memory address of the 0x0 0x8 0x10, when growslice append, the new numerical will be kept to 0x18, but when growslice occurred, all data have been copy to the new address of 0x1000 0x1008 0x1010, the new append value into the 0x1018.

at this time you can understand why you sometimes use unsafe to get the data, and sometimes you can't get it. Maybe you can understand why this package is called unsafe. But unsafe is not really unsafe, that is, if you do not use the wrong posture, it is very easy to unsafe. But if the posture is elegant, it's really safe. For slice, if you want to use unsafe, do remember to pay attention to whether or not to send cap change, it means that the memory of

summary of above

are all the content of this article, I hope this content has a certain reference value of learning to learn or work, if any doubt you can leave a message, thank you for the support of the script.

This paper fixed link: | Script Home | +Copy Link

Article reprint please specify:A number of “pits” encountered in the Go language when slice is passed as a parameter | Script Home

You may also be interested in these articles!