V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
beego
chaleaoch
V2EX  ›  Go

golang 中私有结构体包含公有字段的目的是什么?

  •  
  •   chaleaoch · 5 天前 · 1430 次点击

    在那种应用场景下使用?

    29 条回复    2021-09-15 09:55:40 +08:00
    MidGap
        1
    MidGap   5 天前
    这个有啥问题吗 0.0
    tyx1703
        2
    tyx1703   5 天前 via iPhone   ❤️ 6
    序列化 json 要导出才行
    chaleaoch
        3
    chaleaoch   5 天前
    @MidGap 我觉得可能是 2 楼的原因.

    你有没有考虑过一个私有的结构体, 里面的字段是私有的还是公有的, 其实是没有区别的?'
    除非和 Json 中的反射发生关系, 也就是说 ValueOf 只能获取公有的字段.或者...有什么我不知道的特别的场景.
    chaleaoch
        4
    chaleaoch   5 天前
    @tyx1703 大佬是不是可以理解成序列化只对公有字段有效?
    tyx1703
        5
    tyx1703   5 天前 via iPhone
    @chaleaoch 过誉了,只是经验之谈。

    正常来说是的,不过有 hack 的方法

    https://stackoverflow.com/questions/11126793/json-and-dealing-with-unexported-fields
    chaleaoch
        6
    chaleaoch   5 天前
    @tyx1703 大佬我又有一个新问题...
    https://v2ex.com/t/801812#reply0
    iyear
        7
    iyear   5 天前
    可能是一个第三方包,人家只是想自己在包里调用,不想暴露出去
    MidGap
        8
    MidGap   5 天前
    @chaleaoch 字段是私有还是共有的和这个结构体是私有共有的本来也没啥联系吧~~
    chaleaoch
        9
    chaleaoch   5 天前
    @MidGap 一个结构体是私有的, 那他的字段是私有还是公有已经没有区别了, 从可见性角度看. 反正都是包内生效.

    除非有什么我不知道的 go 语法规则.
    或者像 2 楼说的和 Json/ 反射相关.
    MidGap
        10
    MidGap   5 天前
    @chaleaoch 对对对,就是和反射有关系~
    cyrivlclth
        11
    cyrivlclth   5 天前
    除了反射,还有场景是提供一个默认的全局变量。。。

    var DefaultUserInfo = userInfo{...}

    这个 DefaultUserInfo 是可以导出的。

    userInfo 也可能是某个结构体的一个字段。
    cyrivlclth
        12
    cyrivlclth   5 天前   ❤️ 1
    还有种就是不希望调用方直接使用 UserInfo{}这样的形式使用,而是使用提供的 New 方法去使用
    yin1999
        13
    yin1999   5 天前 via Android
    应该是为了序列化使用(包含了 JSON 的 tag ),而这个结构体本身是不导出的,所以正常使用,它里面的字段是不会被包的使用者直接修改的
    ihipop
        14
    ihipop   5 天前 via Android   ❤️ 1
    结构体私有不代表不能被外部使用,你可以通过一个 new 函数或者包公共变量把它 return 出去
    chaleaoch
        15
    chaleaoch   5 天前
    @cyrivlclth 大佬 这种骚操作的意义是什么?
    chaleaoch
        16
    chaleaoch   5 天前
    @cyrivlclth 骚操作是指 var DefaultUserInfo = userInfo{...}这个.
    =================================
    userInfo 也可能是某个结构体的一个字段。
    譬如叫结构体 AAA 好了, 那么其他包可以通过 AAA 访问 userInfo 吗?
    =================================
    还有种就是不希望调用方直接使用 UserInfo{}这样的形式使用,而是使用提供的 New 方法去使用
    有道理.
    chaleaoch
        17
    chaleaoch   5 天前
    @ihipop
    @cyrivlclth
    工厂方法返回了的结构体 类型 是私有的. 那么调用这个工厂方法的变量如何定义, 只能定义成接口了?
    有没有具体的例子 请大佬赐教.
    chaleaoch
        18
    chaleaoch   5 天前
    接楼上, "那么调用这个工厂方法的变量如何定义" 没说清楚,
    我是指, 调用这个工厂方法的赋值语句需要一个变量接受 New 出来的结构体, 这个变量如何定义. 只有一种可能就是接口.有这么用的么...
    cyrivlclth
        19
    cyrivlclth   5 天前
    @chaleaoch 变量定义直接 var 或者 := 就行呀,又不是老版本的 java 不支持 var
    chaleaoch
        20
    chaleaoch   5 天前
    @cyrivlclth 我试了一下真的可以... 有点假
    cyrivlclth
        21
    cyrivlclth   5 天前
    @chaleaoch =。=你说的那种骚操作我在公司项目中看到过,写这个的人美曰其名是隔离(因为那个 package 导入之后,你按.之后的提示不会有 userInfo,只会有一个 DefaultUserInfo ),但其实在我看来就是没啥大用,就只是本来那个只需要用一次,就定义匿名结构体,但是匿名结构体写法又太难受了,就整个私有但是有公有字段的结构体出来。

    但大部分这种情形都是为了反射。
    cyrivlclth
        22
    cyrivlclth   5 天前
    @chaleaoch 哦,对了,我们那个变量名叫 DefaultConfig,是从 toml 文件解析,所以还真得用公有字段
    chaleaoch
        23
    chaleaoch   5 天前
    @cyrivlclth 谢谢 还剩一个问题 我本地试了一下. 大概明白了 大小写隔离的 是类似链接的功能 并不是内存级别的隔离. 只要我能看见你我就能用你, 而不是从内存检查你到底是否是可见的.
    学到了学到了. 谢谢大佬指点.
    XTTX
        24
    XTTX   4 天前
    上面的答案都不全。struct 里使用 custom type,同时需要自己写符合 marshal unmarshal function signature 的 method.
    XTTX
        25
    XTTX   4 天前
    ============================================
    XTTX
        26
    XTTX   4 天前   ❤️ 1
    你要 unmarshal users.Permissions 就必须提供
    func (u *users.Permissions) UnMarshalJSON() ([]byte, error) { }
    func (u *users.Permissions) MarshalJSON(data []byte) error { }

    你在 marshal 整个 UserInfo 的时候,你提供的针对 users.Permissions 的 marshaller 会自动被调用。
    ============================================================

    比如,很多时候 users.Permissions 是 null, 你不提供上述 method, 整个 marshal 过程会报错。
    XTTX
        27
    XTTX   4 天前
    =================================================
    // NullString is an alias for sql.NullString data type
    type NullString struct {
    sql.NullString
    }

    // MarshalJSON for NullString
    func (ns *NullString) MarshalJSON() ([]byte, error) {
    if !ns.Valid {
    return []byte("null"), nil
    }
    return json.Marshal(ns.String)
    }

    // UnmarshalJSON for NullString
    func (ns *NullString) UnmarshalJSON(b []byte) error {
    err := json.Unmarshal(b, &ns.String)
    ns.Valid = (err == nil)
    return err
    }
    ===================================================

    type ArticleAction struct {
    ID int `db:"articleaction_id" json:"id"`
    Notes NullString `db:"notes,omitempty" json:"notes,omitempty"`
    }
    chaleaoch
        28
    chaleaoch   4 天前
    @XTTX 所以说白了还是和 json 序列化有关系.
    XTTX
        29
    XTTX   4 天前
    @chaleaoch 不然原作者写那么多 json tags 做什么。 数据自产自销不用提供 json tags
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1451 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 17:04 · PVG 01:04 · LAX 10:04 · JFK 13:04
    ♥ Do have faith in what you're doing.