为什么我的字段在函数调用后会被截断?

Dan*_*yel 0 go

http://play.golang.org/p/xFBSZta2CL

我现在已经尝试了2个小时了.进入主要功能,我们立即进入24-26行:

prompter.Define(&Field{"name"})
prompter.Define(&Field{"age"})
Run Code Online (Sandbox Code Playgroud)

define函数:

fmt.Printf("fields: %+v\n", c.fields)
c.fields = append(c.fields, f)
fmt.Printf("fields: %+v\n", c.fields)
Run Code Online (Sandbox Code Playgroud)

函数调用后,c.fields数组再次为空!!! 输出:

fields: []
fields: [0x1040a120]
fields: []
fields: [0x1040a130]
Run Code Online (Sandbox Code Playgroud)

pet*_*rSO 7

Go编程语言

常见问题(FAQ)

我应该在值或指针上定义方法吗?

func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct)  valueMethod()   { } // method on value
Run Code Online (Sandbox Code Playgroud)

对于不习惯指针的程序员来说,这两个例子之间的区别可能令人困惑,但实际情况非常简单.在类型上定义方法时,接收器(上例中的s)的行为就像它是方法的参数一样.然后,将函数参数定义为值还是指针,将接收器定义为值还是指针都是同一个问题.有几个注意事项.

首先,最重要的是,该方法是否需要修改接收器?如果是,接收器必须是指针.(切片和贴图充当引用,因此它们的故事更加微妙,但是例如在接收方必须仍然是指针的方法中更改切片的长度.)在上面的示例中,如果pointerMethod修改了字段s,调用者将看到这些更改,但是使用调用者参数的副本调用valueMethod(这是传递值的定义),因此对调用者所做的更改将对调用者不可见.

顺便说一句,指针接收器与Java中的情况相同,尽管在Java中,指针隐藏在封面下; Go的价值接收器是不寻常的.

其次是效率的考虑.如果接收器很大,例如一个大的结构,使用指针接收器会便宜得多.

接下来是一致性.如果该类型的某些方法必须具有指针接收器,则其余方法也应如此,因此无论使用何种类型,方法集都是一致的.有关详细信息,请参阅方法集部分.

对于诸如基本类型,切片和小结构之类的类型,值接收器非常便宜,因此除非方法的语义需要指针,否则值接收器是高效且清晰的.

在Go中,所有参数和返回值都按值传递.接收者按值传递.使用指针接收器更改值.例如,

package main

import (
    "fmt"
)

type Prompter interface {
    Define(f *Field)
}

type Field struct {
    Key string
}

type Provider interface {
    Prompt(Prompter)
}

var providers = []Provider{
    MyProvider{},
}

type MyProvider struct{}

func (p MyProvider) Prompt(prompter Prompter) {
    prompter.Define(&Field{"name"})
    prompter.Define(&Field{"age"})
}

type CliPrompter struct {
    fields []*Field
}

func NewCliPrompter() *CliPrompter {
    return &CliPrompter{
        fields: make([]*Field, 0, 100),
    }
}

func (c *CliPrompter) Define(f *Field) {
    fmt.Printf("fields: %+v\n", c.fields)
    c.fields = append(c.fields, f)
    fmt.Printf("fields: %+v\n", c.fields)
}

func main() {
    providers[0].Prompt(NewCliPrompter())
}
Run Code Online (Sandbox Code Playgroud)

输出:

fields: []
fields: [0x1040a120]
fields: [0x1040a120]
fields: [0x1040a120 0x1040a130]
Run Code Online (Sandbox Code Playgroud)