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

时间:2015-04-09 01:03:36

标签: go

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

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

prompter.Define(&Field{"name"})
prompter.Define(&Field{"age"})

定义功能:

fmt.Printf("fields: %+v\n", c.fields)
c.fields = append(c.fields, f)
fmt.Printf("fields: %+v\n", c.fields)

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

fields: []
fields: [0x1040a120]
fields: []
fields: [0x1040a130]

1 个答案:

答案 0 :(得分:7)

  

Go编程语言

     

Frequently Asked Questions (FAQ)

     

Should I define methods on values or pointers?

func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct)  valueMethod()   { } // method on value
     

对于不习惯指针的程序员来说,区别   这两个例子可能令人困惑,但事实上情况确实如此   非常简单。在类型上定义方法时,接收器(在   上面的例子)就像它是一个参数一样   方法。是将接收器定义为值还是指针   同样的问题,那么,函数参数是否应该是a   值或指针。有几点需要考虑。

     

首先,最重要的是,该方法是否需要修改   接收器?如果是,接收器必须是指针。 (切片和地图   作为参考,所以他们的故事更微妙,但是   在接收器必须的方法中更改切片长度的实例   仍然是一个指针。)在上面的例子中,如果pointerMethod修改   在s的字段中,调用者将看到这些更改,但valueMethod是   用调用者的参数的副本调用(这是定义的   传递一个值,所以改变它使得调用者看不见。

     

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

     

其次是效率的考虑。如果接收器很大,a   例如,大结构,使用指针要便宜得多   接收机。

     

接下来是一致性。如果该类型的某些方法必须具有   指针接收器,其余的也应该是,所以方法集是   无论使用何种类型,都是一致的。请参阅有关的部分   方法设置细节。

     

对于基本类型,切片和小结构等类型,值   接收器非常便宜,所以除非方法的语义要求   一个指针,一个值接收器是高效和清晰的。

在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())
}

输出:

fields: []
fields: [0x1040a120]
fields: [0x1040a120]
fields: [0x1040a120 0x1040a130]