Go Getter方法与字段,正确命名

时间:2017-07-19 11:24:57

标签: go naming-conventions getter

在Effective Go中,clearly stated表示在未导出字段的情况下(以小写字母开头),getter方法应具有相同的字段名称,但以大写字母开头;他们提供的示例是owner作为字段,Owner作为方法。他们明确建议不要在getter方法名称前面使用Get

我经常遇到需要为JSON编组导出字段,与ORM一起使用或其他与反射相关的目的的情况(IIRC反射可以读取但不能修改未导出的字段),因此需要调用我的字段{ {1}}在上面的示例中,因此无法使用Owner方法。

是否有一种惯用的命名方式可以解决这种情况?

编辑:以下是我遇到的具体示例:

Owner

type User struct {
    Username string `db:"username" json:"username"`
    // ...
}

// code in this package needs to do json.Unmarshal(b, &user), etc.

2 个答案:

答案 0 :(得分:3)

如果导出字段,请不要使用getter和setter。这只会混淆界面。

如果你需要一个getter或setter,因为它做某事(验证,格式化等),或者因为你需要struct来满足一个接口,那么就不要导出底层字段!

如果为了JSON,数据库访问等需要导出的字段,需要getter / setter,那么使用两个结构,一个导出,一个私有,并定义一个自定义JSON封送器(或db访问方法)对公共的一个:

type jsonFoo struct {
    Owner string `json:"owner"`
}

type Foo struct {
    owner string
}

func (f *Foo) SetOwner(username string) {
    // validate/format username
    f.owner = username
}

func (f *Foo) Owner() string {
    return f.owner
}

func (f *Foo) MarshalJSON() ([]byte, error) {
    return json.Marshal(jsonFoo{
        Owner: f.owner,
    })
}

答案 1 :(得分:0)

我会在考虑@Flimzy的答案后得出答案,这很有道理。

基本思想是让一个结构具有可用于编组的导出字段,另一个结构的唯一目的是提供满足所需接口的方法。

这不需要自定义编组代码,并且为每个结构提供了明确的含义,IMO:

type user struct {
    Username string `json:"username"`
}

type ExportedUser struct {
    // EDIT: explicitly doing "user *user" instead of just doing "*user"
    // helps avoid confusion between between field names and methods
    user *user
}

func (u ExportedUser) Username() string { return u.user.Username }

func main() {
    fmt.Printf("Test: %q", ExportedUser{user: &user{Username: "joe"}}.Username())
}

以上是user还是User的问题对我来说有点不清楚 - 因为在Go模板中使用该类型可能是有意义的,例如{{euser.User.SomeOtherField}}因此,如果需要,可以访问所有字段。无论如何,上面的答案都以相同的方式运作。