Note: This article is just my personal note, if there is a fallacy, error, please be sure to point out.
For range issues
Http://stackoverflow.com/questions/30577212/go-for-range-slice-and-goroutine-method-invocation-the-logic-behind
Package main import ("FMT" "Time") Type field struct {name string} func (P *field) print () {FMT . Printf ("Print:p:%p, V:%s\n", p, p.name)} func main () {data: = []field{{"One"},{"one"},{"three"}} for _,v : = Range Data {//NOTE: The iteration variable in the For statement (for example: v) is reused at each iteration and has been reused go v.print ()//Note: Go (&v). Print (), which is a pointer to V To invoke, and V will be reused at each iteration, so each receiver is a pointer to V, and V is assigned a value of "three" after the last iteration, so the result of printing out 3 "three". } time. Sleep (3 * time. Second)//goroutines Print:three, three, three}
Package main import ("FMT" "Time") Type field struct {name string} func (P *field) print () {FMT . Println (P.name)} func main () {data: = []*field{{"One"},{"one"},{"three"}} for _,v: = Range Data {Go V.print ()//v itself is the pointer, pointing to one, the other, the three; The iteration will change the point, the direct call is not copied, the direct call, so each call when the V is pointed to one, two, three address value, of course, will print the correct results; Unlike the previous example, in the above example, because of the multiplexing of V, each invocation of the pointer receiver together points to V, but the value of v after the loop is finally assigned the value: three, so the error result occurs. } time. Sleep (3 * time. Second)}//goroutines Print:one, I, three
Note: Four elements explain the above two examples:
Prerequisite: The method is defined as pointer receiver.
Func (
P *field) print () {fmt. Printf ("Print:p:%p, V:%s\n", p, P.name)}
(1) Pointer receiver does not replicate under the precondition, so when called by value, the &value takes the address directly as Pointer receiver.
(2) If the for _,v: = V in range data is itself a pointer, it is called directly if the condition is met. (3) for range will be reused in each iteration V (4) The Go language itself is a value semantics, that is, the transfer of parameters, calls, iterations are copied, but like: pointers, reference types just copy itself, not its point to the data, so the cost of replication is very low, but the array is a value type, will be copied to the whole yo. Detailed analysis is available in the resources link.
Explanation in StackOverflow: This is a very common technique in go. The iteration variables in the For statement are reused for each iteration. This means that the closure (that is, the function literal) you create in the For loop will refer to the same variable (and the value of that variable will be obtained when those goroutine start executing).
In the first loop, V is the value of a field item. Because V is addressable, it's automatically referenced as the pointer receiver for the print () method. So V.print () are using the address of V itself, and the contents of that address are overwritten each iteration of the loop. When your change of the declaration to use a *field, V is now a pointer to a field value. When you call V.print () in this case, you are operating on the value that V points to, which was stored in data, and the OV Erwriting of V has no effect.
----------------------------------------------------My trial Code---------------------------------package main
Import "FMT" import "Time"
Type A int
Func (A A) valuereceiver () {
Fmt. Printf ("Valuereceiver, P:%p, V:%d\n", &a, a)} func (a A) Valuereceiveringo () {
Fmt. Printf ("Valuereceiveringo, P:%p, v:%d\n", &a, a)} func (a A) Valuereceiverindefer () {
Fmt. Printf ("Valuereceiverindefer, P:%p, v:%d\n", &a, a)}
Func (A A) Valuerececiverinforrange () {
Fmt. Printf ("Valuerececiverinforrange, P:%p, V:%d\n", &a, a)} func main () {var a = 1 fmt. Printf ("Main, p:%p, V:%d\n", &a, a) a.valuereceiver () P: = &a p.valuereceiver ()//------------call in goroutine- -------Go A.valuereceiveringo () go P.valuereceiveringo () time. Sleep (*. Second)//---------call in defer----------defer a.valuereceiverindefer () defer p.valuereceiverindefer ()//---call in For range array, value receiver---as: = [5]a{1,2,3,4,5} fmt. Printf ("as[0]:%p,%d\n", &as[0], as[0]) for _, A: = range as {fmt. Printf ("As in for:%p,%d\n", &as[0], as[0]) fmt. Printf ("A In for:%p, V:%d\n", &a, a) A.valuerececiverinforrange () PF: = &a PF. Valuerececiverinforrange ()}}
Results Main, p:0x10434114, v:1
Valuereceiver, p:0x1043411c, v:1
Valuereceiver, p:0x10434134, v:1
Valuereceiveringo, p:0x1043413c, v:1
Valuereceiveringo, p:0x10434144, v:1
As[0]: 0x10430240, 1
As in for:0x10430240, 1
A in for:0x10434150, v:1
Valuerececiverinforrange, p:0x1043415c, v:1
Valuerececiverinforrange, p:0x10434164, v:1
As in for:0x10430240, 1
A in for:0x10434150, V:2
Valuerececiverinforrange, p:0x10434174, V:2
Valuerececiverinforrange, p:0x1043417c, V:2
As in for:0x10430240, 1
A in for:0x10434150, V:3
Valuerececiverinforrange, p:0x1043418c, V:3
Valuerececiverinforrange, p:0x10434194, V:3
As in for:0x10430240, 1
A in for:0x10434150, V:4
Valuerececiverinforrange, P:0X104341A4, V:4
Valuerececiverinforrange, P:0X104341AC, V:4
As in for:0x10430240, 1
A in for:0x10434150, V:5
Valuerececiverinforrange, P:0X104341BC, V:5
Valuerececiverinforrange, P:0X104341C4, V:5
Valuereceiverindefer, p:0x104341cc, v:1
Valuereceiverindefer, P:0X104341D4, v:1 Conclusion: By analyzing the above address, for the value Receciver method, all kinds of invocation mode, is the copy of the original value, that is, the copy is called Receiver, Even if it is invoked as a pointer, it is called after the copy is generated by *pointer, and it is also noted that a (for _, A: = range as) is reused in the for range.------------------------------------------ ---------------------------------------------------------------------------------Pointer Receiver Test--------------------------
Package Main
Import "FMT" import "Time"
Type A int
Func (P *a) Pointerreceiver () {
Fmt. Printf ("Pointerreceiver, P:%p, V:%d\n", p, *p)} func (P *a) Pointerreceiveringo () {
Fmt. Printf ("Pointerreceiveringo, P:%p, V:%d\n", p, *p)} func (P *a) Pointerreceiverindefer () {
Fmt. Printf ("Pointerreceiverindefer, P:%p, V:%d\n", p, *p)} func (P *a) Pointerreceiverinforrange () {
Fmt. Printf ("Pointerreceiverinforrange, P:%p, V:%d\n", p, *p)} func main () {
var a = 1 fmt. Printf ("Main, p:%p, V:%d\n", &a, a) a.pointerreceiver () P: = &a p.pointerreceiver ()//------------------go A.po Interreceiveringo () go P.pointerreceiveringo () time. Sleep (*. Second)//------------------defer A.pointerreceiverindefer () defer p.pointerreceiverindefer ()//------------------ as: = [5]a{1,2,3,4,5} fmt. Printf ("As[0", p:%p, V:%d\n ", &as[0], as[0]) for _, A: = range as {fmt. Printf ("As in For:p:%p, V:%d\n", &as[0], as[0]) fmt. Printf ("A in for:p:%p, V:%d\n", &a, a) A.pointerreceiverinforrange () P: = &a P.pointerreceiverinforrange ()}}
Results: Main, p:0x10434114, v:1
Pointerreceiver, p:0x10434114, v:1
Pointerreceiver, p:0x10434114, v:1
Pointerreceiveringo, p:0x10434114, v:1
Pointerreceiveringo, p:0x10434114, v:1
As[0], p:0x10430240, v:1
As in For:p: 0x10430240, V:1
A in For:p: 0x10434140, V:1
Pointerreceiverinforrange, p:0x10434140, v:1
Pointerreceiverinforrange, p:0x10434140, v:1
As in For:p: 0x10430240, V:1
A in For:p: 0x10434140, V:2
Pointerreceiverinforrange, p:0x10434140, V:2
Pointerreceiverinforrange, p:0x10434140, V:2
As in For:p: 0x10430240, V:1
A in For:p: 0x10434140, V:3
Pointerreceiverinforrange, p:0x10434140, V:3
Pointerreceiverinforrange, p:0x10434140, V:3
As in For:p: 0x10430240, V:1
A in For:p: 0x10434140, V:4
Pointerreceiverinforrange, p:0x10434140, V:4
Pointerreceiverinforrange, p:0x10434140, V:4
As in For:p: 0x10430240, V:1
A in For:p: 0x10434140, V:5
Pointerreceiverinforrange, p:0x10434140, V:5
Pointerreceiverinforrange, p:0x10434140, V:5
Pointerreceiverindefer, p:0x10434114, v:1
Pointerreceiverindefer, p:0x10434114, v:1
Conclusion: Through the analysis of the above address, for pointer receiver method, at the time of invocation, no copy is generated, but the address of the original object itself; A In (for _, A: = range as) is reused. ---------------------------------------------------------------------------------------------------References:
https://gobyexample.com/http://colobu.com/2015/09/07/gotchas-and-common-mistakes-in-go-golang/http:// Devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/http://waterdudu.github.io/post/go-tips/https ://www.yushuangqi.com/blog/2015/7_things-you-may-not-pay-attation-to-in-go.html http://www.qiukeke.com/2015/05/ 28/gotchas-and-common-mistakes-in-go-golang.html http://tonybai.com/2015/09/17/7- things-you-may-not-pay-attation-to-in-go/
Note: This article is only my personal notes, if there are errors and omissions, please correct me, study together, my e-mail: htyu_0203_39@sina.com