在Go中封装结构

rhu*_*aJi 4 struct go

我是Go的新手.我已经读过Go中的封装是在包级别上.我有一个简单的Web控制器用例.我有一个结构作为一个JSON对象进入,并解组为结构类型.

type User struct{
    Name String `json:"name"`
    //Other Variables
}
Run Code Online (Sandbox Code Playgroud)

现在可以通过json.Unmarshal([] byte)将json解组为User Struct类型.但是,此User结构也可用于其他包.如何确保其他软件包只能访问与User相关的方法.

我能想到的一个解决方案:

type User struct{
    name String
}

type UserJSON struct{
    Name String `json:"name"`
}

func DecodeJSONToUser(rawJSON []byte) (User,error) {
    var userJSON UserJSON
    err := json.Unmarshal(rawJSON,&userJSON)
    //Do error handling
    return User{name:userJSON.Name},nil
}
Run Code Online (Sandbox Code Playgroud)

有没有一种可以实现这一目标的方法?

Ole*_*yar 9

您可以将包本地结构公共字段一起使用,以使此结构在包外不可见.然后你可以使这个结构满足一些公共接口,你有完美的解耦:

package user

import "encoding/json"

type User interface {
    Name() string
}

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

func (u *user) Name() string {
    return "Mr. " + u.Username
}

func ParseUserData(data []byte) (User, error) {
    user := &user{}
    if err := json.Unmarshal(data, user); err != nil {
        return nil, err
    }
    return user, nil
}
Run Code Online (Sandbox Code Playgroud)

并进行相应的测试:

package user_test

import (
    "testing"

    "github.com/teris-io/user"
)

func TestParseUserData(t *testing.T) {
    data := []byte("{\"name\": \"Uncle Sam\"}")
    expected := "Mr. Uncle Sam"
    if usr, err := user.ParseUserData(data); err != nil {
        t.Fatal(err.Error())
    } else if usr.Name() != expected {
        t.Fatalf("expected %s, found %s", expected, usr.Name())
    }
}
Run Code Online (Sandbox Code Playgroud)

➜用户git :(主)✗去测试github.com/teris-io/user

ok github.com/teris-io/user 0.001s

您也可以在解组后将包本地对象转换为某个公共对象.

注意:其中一条评论提到由于名称冲突(user.Name结构上的字段和User.Name接口上的方法)而导致的可怜程度,接口需要具有不同的方法名称.这不是必需的,并且相应地修改了上面的代码:内部结构上的字段可以具有 JSON中的字段不同的名称,相应的注释定义映射.