Golang Go语言中私有结构体包含公有字段的目的是什么?

发布于 1周前 作者 sinazl 来自 Go语言

Golang Go语言中私有结构体包含公有字段的目的是什么?

在那种应用场景下使用?

30 回复

这个有啥问题吗 0.0

更多关于Golang Go语言中私有结构体包含公有字段的目的是什么?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


序列化 json 要导出才行

我觉得可能是 2 楼的原因.

你有没有考虑过一个私有的结构体, 里面的字段是私有的还是公有的, 其实是没有区别的?'
除非和 Json 中的反射发生关系, 也就是说 ValueOf 只能获取公有的字段.或者…有什么我不知道的特别的场景.

大佬是不是可以理解成序列化只对公有字段有效?

过誉了,只是经验之谈。

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

https://stackoverflow.com/questions/11126793/json-and-dealing-with-unexported-fields

可能是一个第三方包,人家只是想自己在包里调用,不想暴露出去

字段是私有还是共有的和这个结构体是私有共有的本来也没啥联系吧~~

一个结构体是私有的, 那他的字段是私有还是公有已经没有区别了, 从可见性角度看. 反正都是包内生效.

除非有什么我不知道的 go 语法规则.
或者像 2 楼说的和 Json/ 反射相关.

对对对,就是和反射有关系~

除了反射,还有场景是提供一个默认的全局变量。。。

var DefaultUserInfo = userInfo{…}

这个 DefaultUserInfo 是可以导出的。

userInfo 也可能是某个结构体的一个字段。

还有种就是不希望调用方直接使用 UserInfo{}这样的形式使用,而是使用提供的 New 方法去使用

应该是为了序列化使用(包含了 JSON 的 tag ),而这个结构体本身是不导出的,所以正常使用,它里面的字段是不会被包的使用者直接修改的

结构体私有不代表不能被外部使用,你可以通过一个 new 函数或者包公共变量把它 return 出去

大佬 这种骚操作的意义是什么?

骚操作是指 var DefaultUserInfo = userInfo{…}这个.
=================================
userInfo 也可能是某个结构体的一个字段。
譬如叫结构体 AAA 好了, 那么其他包可以通过 AAA 访问 userInfo 吗?
=================================
还有种就是不希望调用方直接使用 UserInfo{}这样的形式使用,而是使用提供的 New 方法去使用
有道理.



工厂方法返回了的结构体 类型 是私有的. 那么调用这个工厂方法的变量如何定义, 只能定义成接口了?
有没有具体的例子 请大佬赐教.

接楼上, “那么调用这个工厂方法的变量如何定义” 没说清楚,
我是指, 调用这个工厂方法的赋值语句需要一个变量接受 New 出来的结构体, 这个变量如何定义. 只有一种可能就是接口.有这么用的么…

变量定义直接 var 或者 := 就行呀,又不是老版本的 java 不支持 var

我试了一下真的可以… 有点假

=。=你说的那种骚操作我在公司项目中看到过,写这个的人美曰其名是隔离(因为那个 package 导入之后,你按.之后的提示不会有 userInfo,只会有一个 DefaultUserInfo ),但其实在我看来就是没啥大用,就只是本来那个只需要用一次,就定义匿名结构体,但是匿名结构体写法又太难受了,就整个私有但是有公有字段的结构体出来。

但大部分这种情形都是为了反射。

哦,对了,我们那个变量名叫 DefaultConfig,是从 toml 文件解析,所以还真得用公有字段

谢谢 还剩一个问题 我本地试了一下. 大概明白了 大小写隔离的 是类似链接的功能 并不是内存级别的隔离. 只要我能看见你我就能用你, 而不是从内存检查你到底是否是可见的.
学到了学到了. 谢谢大佬指点.

上面的答案都不全。struct 里使用 custom type,同时需要自己写符合 marshal unmarshal function signature 的 method.

============================================

你要 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 过程会报错。

=================================================
// 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"
}

所以说白了还是和 json 序列化有关系.

不然原作者写那么多 json tags 做什么。 数据自产自销不用提供 json tags

在Golang(Go语言)中,私有结构体包含公有字段的设计通常是为了实现封装和信息隐藏的同时,提供一定的灵活性和可控的访问权限。这种做法有几个主要目的:

  1. 封装和抽象:私有结构体确保外部代码不能直接访问或修改其内部状态,从而保护了数据的完整性和业务逻辑的一致性。公有字段允许通过特定的方法(如getter和setter)来访问和修改数据,这样可以增加额外的逻辑处理,如验证、计算或日志记录。

  2. 控制访问权限:通过公开必要的字段和提供方法来操作这些字段,开发者可以精确控制哪些数据可以被外部访问和修改,哪些操作是允许的,从而避免误用和潜在的安全问题。

  3. 灵活性:虽然结构体本身是私有的,但公开字段允许在不暴露整个结构体的情况下,与外部代码进行交互。这提供了一种平衡,既保持了内部实现的封装性,又允许一定程度的外部访问。

  4. 接口实现:有时候,私有结构体需要实现一个或多个接口,而这些接口要求结构体公开某些字段或方法。在这种情况下,公开必要的字段有助于满足接口规范,同时仍然保持结构体的私有性和封装性。

总之,私有结构体包含公有字段是Go语言中一种常见的实践,旨在通过封装和接口提供灵活且安全的代码设计,同时确保数据的一致性和安全性。

回到顶部