Update field if value is nil, 0, false in struct golang?

huangapple go评论103阅读模式
英文:

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 (
&quot;errors&quot;
&quot;fmt&quot;
&quot;log&quot;
&quot;reflect&quot;
&quot;time&quot;
)
type User struct {
ID       int    `json:&quot;id&quot;`
Username string `json:&quot;username&quot;`
About    string `json:&quot;about&quot;`
IsAdmin  bool   `json:&quot;is_admin&quot;`
Status   int    `json:&quot;status&quot;`
Date     *time.Time
}
func main() {
now := time.Now()
ua := User{
ID:       1,
Username: &quot;admin&quot;,
About:    &quot;I am an admin&quot;,
IsAdmin:  true,
Status:   1,
Date:     &amp;now,
}
ub := User{
Username: &quot;user&quot;,
}
fmt.Printf(&quot;ua: %+v\n&quot;, ua)
fmt.Printf(&quot;ub: %+v\n&quot;, ub)
err := Replace(ua, &amp;ub)
if err != nil {
log.Fatal(err)
}
fmt.Printf(&quot;\nua: %+v\n&quot;, ua)
fmt.Printf(&quot;ub: %+v\n&quot;, 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(&quot;a is not a struct&quot;)
}
// Check b.
vb := reflect.ValueOf(b)
if vb.Kind() != reflect.Ptr {
return errors.New(&quot;b is not a pointer&quot;)
}
// 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(&quot;b is not a struct&quot;)
}
for i := 0; i &lt; vb.NumField(); i++ {
field := vb.Field(i)
if field.CanInterface() &amp;&amp; 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:&lt;nil&gt;}
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 := &amp;User{1,&quot;admin&quot;, &quot;I am a admin&quot;,status: 1,....}
if A != nil {
fmt.Println(A)
} else {
fmt.Println(&quot;nil object&quot;)
}

There is not reason to check if fields of the object are default values.

huangapple
  • 本文由 发表于 2017年5月11日 18:23:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/43912734.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定