Json 隐藏结构字段并使其同步访问和修改字段的最佳方法是什么?
这是我在使用golang结构时面临的一个问题Json 隐藏结构字段并使其同步访问和修改字段的最佳方法是什么?,json,go,struct,concurrency,mutex,Json,Go,Struct,Concurrency,Mutex,这是我在使用golang结构时面临的一个问题 type User struct { name string `json:"name"` email string `json:"email"` } 现在我希望这个结构字段的访问和修改是并发安全的 因此,我们添加了一个互斥体,并添加了锁定互斥体的方法 用户代码现在只能通过方法访问和变异,不能直接访问字段 type User struct { name string `json:"name"` emai
type User struct {
name string `json:"name"`
email string `json:"email"`
}
现在我希望这个结构字段的访问和修改是并发安全的
因此,我们添加了一个互斥体,并添加了锁定互斥体的方法
用户代码现在只能通过方法访问和变异,不能直接访问字段
type User struct {
name string `json:"name"`
email string `json:"email"`
sync.RWMutex `json:"-"`
}
func (u *User) Name() string {
u.RLock()
defer u.RUnlock()
return u.name
}
func (u *User) Email() string {
u.RLock()
defer u.RUnlock()
return u.email
}
func (u *User) SetName(p string) {
u.Lock()
defer u.Unlock()
u.name = p
}
func (u *User) SetEmail(p string) {
u.RLock()
defer u.RUnlock()
u.email = p
}
到目前为止还不错,但问题是json/bson编组失败,因为它需要导出字段
func (self User) MarshalJSON() ([]byte, error) {
var usr struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
sync.RWMutex `json:"-"`
}
return json.Marshal(usr)
}
func (self *User) UnmarshalJSON(b []byte) error {
var usr struct {
Name string `json:"name"`
Email string `json:"email"`
sync.RWMutex `json:"-"`
}
if err := json.Unmarshal(b, &usr); err != nil {
return err
}
self.name = usr.Name
self.email = usr.Email
return nil
}
因此,我实现了自定义封送,它返回一个类似的结构,但带有导出字段
func (self User) MarshalJSON() ([]byte, error) {
var usr struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
sync.RWMutex `json:"-"`
}
return json.Marshal(usr)
}
func (self *User) UnmarshalJSON(b []byte) error {
var usr struct {
Name string `json:"name"`
Email string `json:"email"`
sync.RWMutex `json:"-"`
}
if err := json.Unmarshal(b, &usr); err != nil {
return err
}
self.name = usr.Name
self.email = usr.Email
return nil
}
但这并不能完全保证用户结构并发的安全,因为marhsaling代码没有被锁定
我的问题是如何使编组代码使用相同的互斥?
当我们创建结构的多个实例时,将互斥锁设置为全局并不能解决问题。
封送处理中声明的用户结构与主用户结构不同,因此锁定内部结构的互斥体是没有意义的
实现这一点的最佳方法是什么?您不必向封送的值添加互斥,这是毫无意义的 但在复制或设置其字段时,确实需要使用
用户的互斥体
一些重要的事情:
func (u *User) MarshalJSON() ([]byte, error) {
u.RLock()
usr := struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
}{u.name, u.email}
u.RUnlock()
return json.Marshal(usr)
}
func (u *User) UnmarshalJSON(b []byte) error {
usr := struct {
Name string `json:"name"`
Email string `json:"email"`
}{}
if err := json.Unmarshal(b, &usr); err != nil {
return err
}
u.Lock()
u.name = usr.Name
u.email = usr.Email
u.Unlock()
return nil
}
- 如果嵌入非指针互斥体,则必须使用指针接收器指定所有方法,否则将复制锁李>
- 您不需要在未报告的字段上指定
json
标记,这是多余的。更进一步,由于您提供了自己的封送逻辑,您甚至不必提供任何json
标记,因为它们根本不会被使用。所以这个用户
就足够了:
type User struct {
name string
email string
sync.RWMutex
}
- 即使
name
和email
未报告,这些值也不是“安全的”,因为您提供了一个导出的MarshalJSON()
方法,该方法返回这些值(JSON格式)。对于访问User.name
和User.email
,您仍然具有编译时安全性,但要知道它们存储的值不是秘密的
示例:
func (u *User) MarshalJSON() ([]byte, error) {
u.RLock()
usr := struct {
Name string `json:"name"`
Email string `json:"email,omitempty"`
}{u.name, u.email}
u.RUnlock()
return json.Marshal(usr)
}
func (u *User) UnmarshalJSON(b []byte) error {
usr := struct {
Name string `json:"name"`
Email string `json:"email"`
}{}
if err := json.Unmarshal(b, &usr); err != nil {
return err
}
u.Lock()
u.name = usr.Name
u.email = usr.Email
u.Unlock()
return nil
}
“如果嵌入非指针互斥体,则必须使用指针接收器指定所有方法,否则将复制锁!”:完成。我们有一个过梁来检查。我以一种艰难的方式了解到了这一点:“你不必向封送的值添加互斥,这是毫无意义的。”我理解你的意思是,由于结构正在初始化,因此目前没有并发访问问题。就像java构造函数不能声明为synchronized一样。感谢您确认我想得太多:-)“尽管name和email未被报告,但这些值并不“安全”,因为您提供了一个导出的MarshalJSON()方法,该方法返回这些值(JSON格式)。对于访问User.name和User.email,您仍然具有编译时安全性,但要知道它们存储的值不是秘密的。”你说得对,但在我的情况下,这并不重要。但这并不妨碍go race检测器将其标记为数据竞赛。我可以理解为什么它们是同时访问同一字段的两个函数。现在,我们不得不忽略it@rajeshnair这不应该导致数据竞争,因为每当访问User
的字段时,它们总是受到互斥锁的保护。你不应该忽视数据竞争。上面的代码没有任何种族。