有人可以向我解释为什么在执行此操作时附加到数组会起作用:
func (s *Sample) Append(name string) {
d := &Stuff{
name: name,
}
s.data = append(s.data, d)
}
但不是在你这样做的时候:
func (s Sample) Append(name string) {
d := &Stuff{
name: name,
}
s.data = append(s.data, d)
}
你有什么理由想要使用第二个例子。
答案 0 :(得分:42)
如上所述in the FAQ
func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct) valueMethod() { } // method on value
首先,最重要的是,该方法是否需要修改接收器?如果是这样,接收器必须是一个指针。(切片和贴图充当参考,所以他们的故事更微妙,但是例如在方法中改变切片的长度接收器必须仍然是指针。)
在上面的示例中,如果pointerMethod修改了s的字段,则调用者将看到这些更改,但是使用调用者参数的副本调用valueMethod('是传递值的定义),因此对调用者来说,它所做的更改是不可见的。
在您的情况下,func (s Sample) Append(name string)
会修改副本。
laher提醒我们in the comments使用值代替指针也意味着获取副本,并尊重对象的不可变性质::
你想要使用非指针
valueMethod
(当然)你要返回一个[来自一个不可变的'的值]。私有财产。
请参阅" Why are receivers pass by value in Go?":
如果您有一个小的不可变对象,则可能很有用。呼叫者可以确定该方法不会修改它的接收者 如果接收器是指针而不首先读取代码,他们就无法知道这一点。
答案 1 :(得分:8)
[]int
)如下所示:
struct {
data *int // pointer to the data area
len int
cap int
}
将切片传递给函数时,此结构通过值传递,而不复制基础数据区域(即data
指向的内容)。内置append()
函数修改data
区域(或生成新区域)并返回包含更新的len
,data
和cap
值的新切片。如果要覆盖不属于基础数据区域的任何内容,则需要将指针传递给切片或返回修改后的切片。
答案 2 :(得分:1)
除非使用指针,否则按值传递参数,而不是按引用传递参数。因此,在函数内部,如果只是按值传递,则不会在任何外部作用域中修改 s 。但是,当您传递指针时,您可以修改“真实”变量,而不仅仅是函数内部存在的副本。
答案 3 :(得分:0)
尽管这里的大多数答案都准确地描述了发生的事情,但我想深入了解一下发生的情况。我从几小段代码开始:
指针方法
package main
import "fmt"
type Bar struct{}
func (b *Bar) Print() {
fmt.Println("debosmit ray")
}
func main() {
b := Bar{}
b.Print()
}
值方法
package main
import "fmt"
type Bar struct{}
func (b Bar) Print() {
fmt.Println("debosmit ray")
}
func main() {
b := Bar{}
b.Print()
}
然后,我只想查看文件的汇编(每个文件使用go tool compile -S filename.go > filename.S
生成。两个输出都可用here(应该永远可用)。
让我们看一下diff pointer.S value.S
的输出(指针->具有指针方法,值->具有value方法)。
14,15c14,15
< "".(*Bar).Print STEXT size=138 args=0x8 locals=0x58
< 0x0000 00000 (bar.go:7) TEXT "".(*Bar).Print(SB), ABIInternal, $88-8
---
> "".Bar.Print STEXT size=138 args=0x0 locals=0x58
> 0x0000 00000 (bar.go:7) TEXT "".Bar.Print(SB), ABIInternal, $88-0
24c24
< 0x001d 00029 (bar.go:7) FUNCDATA $0, gclocals·2a5305abe05176240e61b8620e19a815(SB)
---
> 0x001d 00029 (bar.go:7) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
26c26
< 0x001d 00029 (bar.go:7) FUNCDATA $3, "".(*Bar).Print.stkobj(SB)
---
> 0x001d 00029 (bar.go:7) FUNCDATA $3, "".Bar.Print.stkobj(SB)
126a127,200
> "".(*Bar).Print STEXT dupok size=187 args=0x8 locals=0x58
> 0x0000 00000 (<autogenerated>:1) TEXT "".(*Bar).Print(SB), DUPOK|WRAPPER|ABIInternal, $88-8
> 0x0000 00000 (<autogenerated>:1) MOVQ (TLS), CX
> 0x0009 00009 (<autogenerated>:1) CMPQ SP, 16(CX)
> 0x000d 00013 (<autogenerated>:1) PCDATA $0, $-2
> 0x000d 00013 (<autogenerated>:1) JLS 154
> 0x0013 00019 (<autogenerated>:1) PCDATA $0, $-1
> 0x0013 00019 (<autogenerated>:1) SUBQ $88, SP
> 0x0017 00023 (<autogenerated>:1) MOVQ BP, 80(SP)
> 0x001c 00028 (<autogenerated>:1) LEAQ 80(SP), BP
> 0x0021 00033 (<autogenerated>:1) MOVQ 32(CX), BX
> 0x0025 00037 (<autogenerated>:1) TESTQ BX, BX
> 0x0028 00040 (<autogenerated>:1) JNE 165
> 0x002a 00042 (<autogenerated>:1) NOP
> 0x002a 00042 (<autogenerated>:1) FUNCDATA $0, gclocals·1a65e721a2ccc325b382662e7ffee780(SB)
> 0x002a 00042 (<autogenerated>:1) FUNCDATA $1, gclocals·2589ca35330fc0fce83503f4569854a0(SB)
> 0x002a 00042 (<autogenerated>:1) FUNCDATA $3, "".(*Bar).Print.stkobj(SB)
> 0x002a 00042 (<autogenerated>:1) CMPQ ""..this+96(SP), $0
> 0x0030 00048 (<autogenerated>:1) JEQ 148
> 0x0032 00050 (<unknown line number>) NOP
> 0x0032 00050 (bar.go:8) XORPS X0, X0
> 0x0035 00053 (bar.go:8) MOVUPS X0, ""..autotmp_13+64(SP)
> 0x003a 00058 (bar.go:8) LEAQ type.string(SB), AX
> 0x0041 00065 (bar.go:8) MOVQ AX, ""..autotmp_13+64(SP)
> 0x0046 00070 (bar.go:8) LEAQ ""..stmp_2(SB), AX
> 0x004d 00077 (bar.go:8) MOVQ AX, ""..autotmp_13+72(SP)
> 0x0052 00082 (<unknown line number>) NOP
> 0x0052 00082 ($GOROOT/src/fmt/print.go:274) MOVQ os.Stdout(SB), AX
> 0x0059 00089 ($GOROOT/src/fmt/print.go:274) LEAQ go.itab.*os.File,io.Writer(SB), CX
> 0x0060 00096 ($GOROOT/src/fmt/print.go:274) MOVQ CX, (SP)
> 0x0064 00100 ($GOROOT/src/fmt/print.go:274) MOVQ AX, 8(SP)
> 0x0069 00105 ($GOROOT/src/fmt/print.go:274) LEAQ ""..autotmp_13+64(SP), AX
> 0x006e 00110 ($GOROOT/src/fmt/print.go:274) MOVQ AX, 16(SP)
> 0x0073 00115 ($GOROOT/src/fmt/print.go:274) MOVQ $1, 24(SP)
> 0x007c 00124 ($GOROOT/src/fmt/print.go:274) MOVQ $1, 32(SP)
> 0x0085 00133 ($GOROOT/src/fmt/print.go:274) PCDATA $1, $1
> 0x0085 00133 ($GOROOT/src/fmt/print.go:274) CALL fmt.Fprintln(SB)
> 0x008a 00138 (bar.go:8) MOVQ 80(SP), BP
> 0x008f 00143 (bar.go:8) ADDQ $88, SP
> 0x0093 00147 (bar.go:8) RET
> 0x0094 00148 (<autogenerated>:1) CALL runtime.panicwrap(SB)
> 0x0099 00153 (<autogenerated>:1) XCHGL AX, AX
> 0x009a 00154 (<autogenerated>:1) NOP
> 0x009a 00154 (<autogenerated>:1) PCDATA $1, $-1
> 0x009a 00154 (<autogenerated>:1) PCDATA $0, $-2
> 0x009a 00154 (<autogenerated>:1) CALL runtime.morestack_noctxt(SB)
> 0x009f 00159 (<autogenerated>:1) PCDATA $0, $-1
> 0x009f 00159 (<autogenerated>:1) NOP
> 0x00a0 00160 (<autogenerated>:1) JMP 0
> 0x00a5 00165 (<autogenerated>:1) LEAQ 96(SP), DI
> 0x00aa 00170 (<autogenerated>:1) CMPQ (BX), DI
> 0x00ad 00173 (<autogenerated>:1) JNE 42
> 0x00b3 00179 (<autogenerated>:1) MOVQ SP, (BX)
> 0x00b6 00182 (<autogenerated>:1) JMP 42
> 0x0000 65 48 8b 0c 25 00 00 00 00 48 3b 61 10 0f 86 87 eH..%....H;a....
> 0x0010 00 00 00 48 83 ec 58 48 89 6c 24 50 48 8d 6c 24 ...H..XH.l$PH.l$
> 0x0020 50 48 8b 59 20 48 85 db 75 7b 48 83 7c 24 60 00 PH.Y H..u{H.|$`.
> 0x0030 74 62 0f 57 c0 0f 11 44 24 40 48 8d 05 00 00 00 tb.W...D$@H.....
> 0x0040 00 48 89 44 24 40 48 8d 05 00 00 00 00 48 89 44 .H.D$@H......H.D
> 0x0050 24 48 48 8b 05 00 00 00 00 48 8d 0d 00 00 00 00 $HH......H......
> 0x0060 48 89 0c 24 48 89 44 24 08 48 8d 44 24 40 48 89 H..$H.D$.H.D$@H.
> 0x0070 44 24 10 48 c7 44 24 18 01 00 00 00 48 c7 44 24 D$.H.D$.....H.D$
> 0x0080 20 01 00 00 00 e8 00 00 00 00 48 8b 6c 24 50 48 .........H.l$PH
> 0x0090 83 c4 58 c3 e8 00 00 00 00 90 e8 00 00 00 00 90 ..X.............
> 0x00a0 e9 5b ff ff ff 48 8d 7c 24 60 48 39 3b 0f 85 77 .[...H.|$`H9;..w
> 0x00b0 ff ff ff 48 89 23 e9 6f ff ff ff ...H.#.o...
> rel 5+4 t=17 TLS+0
> rel 61+4 t=16 type.string+0
> rel 73+4 t=16 ""..stmp_2+0
> rel 85+4 t=16 os.Stdout+0
> rel 92+4 t=16 go.itab.*os.File,io.Writer+0
> rel 134+4 t=8 fmt.Fprintln+0
> rel 149+4 t=8 runtime.panicwrap+0
> rel 155+4 t=8 runtime.morestack_noctxt+0
139,143c213,217
< go.info."".(*Bar).Print$abstract SDWARFINFO dupok size=26
< 0x0000 04 2e 28 2a 42 61 72 29 2e 50 72 69 6e 74 00 01 ..(*Bar).Print..
< 0x0010 01 11 62 00 00 00 00 00 00 00 ..b.......
< rel 0+0 t=24 type.*"".Bar+0
< rel 21+4 t=29 go.info.*"".Bar+0
---
> go.info."".Bar.Print$abstract SDWARFINFO dupok size=23
> 0x0000 04 2e 42 61 72 2e 50 72 69 6e 74 00 01 01 11 62 ..Bar.Print....b
> 0x0010 00 00 00 00 00 00 00 .......
> rel 0+0 t=24 type."".Bar+0
> rel 18+4 t=29 go.info."".Bar+0
297c371,392
< type."".Bar SRODATA size=96
---
> type..namedata.*func(main.Bar)- SRODATA dupok size=18
> 0x0000 00 00 0f 2a 66 75 6e 63 28 6d 61 69 6e 2e 42 61 ...*func(main.Ba
> 0x0010 72 29 r)
> type.*func("".Bar) SRODATA dupok size=56
> 0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
> 0x0010 7f 95 9a 2f 08 08 08 36 00 00 00 00 00 00 00 00 .../...6........
> 0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> 0x0030 00 00 00 00 00 00 00 00 ........
> rel 24+8 t=1 runtime.memequal64·f+0
> rel 32+8 t=1 runtime.gcbits.01+0
> rel 40+4 t=5 type..namedata.*func(main.Bar)-+0
> rel 48+8 t=1 type.func("".Bar)+0
> type.func("".Bar) SRODATA dupok size=64
> 0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 ................
> 0x0010 b4 2e bc 27 02 08 08 33 00 00 00 00 00 00 00 00 ...'...3........
> 0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> 0x0030 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
> rel 32+8 t=1 runtime.gcbits.01+0
> rel 40+4 t=5 type..namedata.*func(main.Bar)-+0
> rel 44+4 t=6 type.*func("".Bar)+0
> rel 56+8 t=1 type."".Bar+0
> type."".Bar SRODATA size=112
303c398,399
< 0x0050 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 00 ................
---
> 0x0050 00 00 00 00 01 00 01 00 10 00 00 00 00 00 00 00 ................
> 0x0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
309a406,409
> rel 96+4 t=5 type..namedata.Print.+0
> rel 100+4 t=25 type.func()+0
> rel 104+4 t=25 "".(*Bar).Print+0
> rel 108+4 t=25 "".Bar.Print+0
320a421,423
> ""..stmp_2 SRODATA size=16
> 0x0000 00 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 ................
> rel 0+8 t=1 go.string."debosmit ray"+0
325,326c428,429
< gclocals·2a5305abe05176240e61b8620e19a815 SRODATA dupok size=9
< 0x0000 01 00 00 00 01 00 00 00 00 .........
---
> gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
> 0x0000 01 00 00 00 00 00 00 00 ........
329c432
< "".(*Bar).Print.stkobj SRODATA size=24
---
> "".Bar.Print.stkobj SRODATA size=24
333,334d435
< gclocals·33cdeccccebe80329f1fdbee7f5874cb SRODATA dupok size=8
< 0x0000 01 00 00 00 00 00 00 00 ........
338a440,447
> gclocals·1a65e721a2ccc325b382662e7ffee780 SRODATA dupok size=10
> 0x0000 02 00 00 00 01 00 00 00 01 00 ..........
> gclocals·2589ca35330fc0fce83503f4569854a0 SRODATA dupok size=10
> 0x0000 02 00 00 00 02 00 00 00 00 00 ..........
> "".(*Bar).Print.stkobj SRODATA dupok size=24
> 0x0000 01 00 00 00 00 00 00 00 f0 ff ff ff ff ff ff ff ................
> 0x0010 00 00 00 00 00 00 00 00 ........
> rel 16+8 t=1 type.[1]interface {}+0
很明显,对于值方法而言:
b
的调用,创建了b.Print()
的副本rel 0+8 t=1 go.string."debosmit ray"+0
的副本。因此,当使用值指针时,这进一步具体化了: