英文:
Update field if value is nil, 0, false in struct golang?
问题
我有一个结构体:
type User struct {
ID int `json:"id"`
Username string `json:"username"`
About string `json:"about"`
IsAdmin bool `json:"is_admin"`
Status int `json:"status"`
......
}
A := User{1, "admin", "我是管理员", true, 1, ....}
B := User{ID: 1, Username: "UserBBBB"}
...输入代码...
B 是 {1, "UserBBBB", "我是管理员", true, ...(与 A 中相同的值)}
对象 B 的一些属性为 nil(字符串)、false(布尔值)、0(整数)等。
我想检查 B 的字段是否为未分配的值,如果是,则该字段将接收 A 中相同字段的值。
例如:
B 的 About 字段为 nil;
A 的 About 字段为 "我是管理员"。
我希望 B 的 About 字段为 "我是管理员"。
我可以编写以下代码:
if len(B.About) == 0 {
B.About = A.About
}
对于其他字段也是类似的,我不想逐个字段进行检查。
英文:
I have a struct:
type User struct {
ID int `json:"id"`
Username string `json:"username"`
About string `json:"about"`
IsAdmin bool `json:"is_admin"`
Status int `json:"status"`
......
}
A:= User{1,"admin", "I am a admin",status: 1,....}
B:= User{ID:1, Username: "UserBBBB"}
...enter code here...
B is {1, "UserBBBB", "I am a admin", 1, ...(same value in A)}
object B has a few properties with nil (string), false (bool), 0 (int),...
I want to check if a field of B is unassigned value, that field will receive value of the same field in A,
example:
B's About field is nil;
A's About field is "I am a admin"
I want to B's About field is "I am a admin".
I can write code:
if len(B.About) == 0 {
B.About = A.About
}
Similar to other fields, I don't want check step by step with all of fields.
答案1
得分: 2
package main
import (
"errors"
"fmt"
"log"
"reflect"
"time"
)
type User struct {
ID int `json:"id"`
Username string `json:"username"`
About string `json:"about"`
IsAdmin bool `json:"is_admin"`
Status int `json:"status"`
Date *time.Time
}
func main() {
now := time.Now()
ua := User{
ID: 1,
Username: "admin",
About: "I am an admin",
IsAdmin: true,
Status: 1,
Date: &now,
}
ub := User{
Username: "user",
}
fmt.Printf("ua: %+v\n", ua)
fmt.Printf("ub: %+v\n", ub)
err := Replace(ua, &ub)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nua: %+v\n", ua)
fmt.Printf("ub: %+v\n", ub)
}
// IsZeroOfUnderlyingType return wether x is the is
// the zero-value of its underlying type.
func IsZeroOfUnderlyingType(x interface{}) bool {
return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}
// Replace replaces all fields of struct b that have a
// zero-value with the corresponding field value from a.
// b must be a pointer to a struct.
func Replace(a, b interface{}) error {
// Check a.
va := reflect.ValueOf(a)
if va.Kind() != reflect.Struct {
return errors.New("a is not a struct")
}
// Check b.
vb := reflect.ValueOf(b)
if vb.Kind() != reflect.Ptr {
return errors.New("b is not a pointer")
}
// vb is a pointer, indirect it to get the
// underlying value, and make sure it is a struct.
vb = vb.Elem()
if vb.Kind() != reflect.Struct {
return errors.New("b is not a struct")
}
for i := 0; i < vb.NumField(); i++ {
field := vb.Field(i)
if field.CanInterface() && IsZeroOfUnderlyingType(field.Interface()) {
// This field have a zero-value.
// Search in a for a field with the same name.
name := vb.Type().Field(i).Name
fa := va.FieldByName(name)
if fa.IsValid() {
// Field with name was found in struct a,
// assign its value to the field in b.
if field.CanSet() {
field.Set(fa)
}
}
}
}
return nil
}
输出
ua: {ID:1 Username:admin About:I am an admin IsAdmin:true Status:1 Date:2017-05-11 17:47:30.805657327 +0200 CEST}
ub: {ID:0 Username:user About: IsAdmin:false Status:0 Date:<nil>}
ua: {ID:1 Username:admin About:I am an admin IsAdmin:true Status:1 Date:2017-05-11 17:47:30.805657327 +0200 CEST}
ub: {ID:1 Username:user About:I am an admin IsAdmin:true Status:1 Date:2017-05-11 17:47:30.805657327 +0200 CEST}
英文:
package main
import (
"errors"
"fmt"
"log"
"reflect"
"time"
)
type User struct {
ID int `json:"id"`
Username string `json:"username"`
About string `json:"about"`
IsAdmin bool `json:"is_admin"`
Status int `json:"status"`
Date *time.Time
}
func main() {
now := time.Now()
ua := User{
ID: 1,
Username: "admin",
About: "I am an admin",
IsAdmin: true,
Status: 1,
Date: &now,
}
ub := User{
Username: "user",
}
fmt.Printf("ua: %+v\n", ua)
fmt.Printf("ub: %+v\n", ub)
err := Replace(ua, &ub)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nua: %+v\n", ua)
fmt.Printf("ub: %+v\n", ub)
}
// IsZeroOfUnderlyingType return wether x is the is
// the zero-value of its underlying type.
func IsZeroOfUnderlyingType(x interface{}) bool {
return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}
// Replace replaces all fields of struct b that have a
// zero-value with the corresponding field value from a.
// b must be a pointer to a struct.
func Replace(a, b interface{}) error {
// Check a.
va := reflect.ValueOf(a)
if va.Kind() != reflect.Struct {
return errors.New("a is not a struct")
}
// Check b.
vb := reflect.ValueOf(b)
if vb.Kind() != reflect.Ptr {
return errors.New("b is not a pointer")
}
// vb is a pointer, indirect it to get the
// underlying value, and make sure it is a struct.
vb = vb.Elem()
if vb.Kind() != reflect.Struct {
return errors.New("b is not a struct")
}
for i := 0; i < vb.NumField(); i++ {
field := vb.Field(i)
if field.CanInterface() && IsZeroOfUnderlyingType(field.Interface()) {
// This field have a zero-value.
// Search in a for a field with the same name.
name := vb.Type().Field(i).Name
fa := va.FieldByName(name)
if fa.IsValid() {
// Field with name was found in struct a,
// assign its value to the field in b.
if field.CanSet() {
field.Set(fa)
}
}
}
}
return nil
}
Output
ua: {ID:1 Username:admin About:I am an admin IsAdmin:true Status:1 Date:2017-05-11 17:47:30.805657327 +0200 CEST}
ub: {ID:0 Username:user About: IsAdmin:false Status:0 Date:<nil>}
ua: {ID:1 Username:admin About:I am an admin IsAdmin:true Status:1 Date:2017-05-11 17:47:30.805657327 +0200 CEST}
ub: {ID:1 Username:user About:I am an admin IsAdmin:true Status:1 Date:2017-05-11 17:47:30.805657327 +0200 CEST}
答案2
得分: -1
如果我正确理解你要完成的任务,你最好使用对象的指针而不是对象本身。
例如,
A := &User{1, "admin", "我是管理员", status: 1,....}
if A != nil {
fmt.Println(A)
} else {
fmt.Println("空对象")
}
没有理由检查对象的字段是否是默认值。
英文:
If I correctly understand what you are going to accomplish, you should better use pointers to objects instead of objects.
For example,
A := &User{1,"admin", "I am a admin",status: 1,....}
if A != nil {
fmt.Println(A)
} else {
fmt.Println("nil object")
}
There is not reason to check if fields of the object are default values.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论