使用反射在结构体中将 Golang 的 nil 字符串指针值设置为 nil。

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

Golang set nil string pointer value in struct using reflect

问题

使用Go的reflect包,是否有办法在结构体中设置一个指针,即使该指针为nil?查看reflect包,如果reflect.Value.CanSet()false,那么任何Set()调用都会导致恐慌。是否有另一种方法来解决这个问题,只使用reflect包,而不依赖于对结构体的直接引用?例如,如何在下面的代码中将空的姓氏设置为"Johnson"?

package main

import (
	"fmt"
	"reflect"
)

type Person struct {
	FirstName *string
	LastName  *string
}

func main() {
	p := Person{}
	firstName := "Ryan"
	p.FirstName = &firstName

	rp := reflect.ValueOf(p)
	fmt.Println("rp:", rp)

	for i := 0; i < rp.NumField(); i++ {
		fmt.Printf("%s: Pointer: %d CanSet: %t\n", rp.Type().Field(i).Name, rp.Field(i).Pointer(), rp.Field(i).Elem().CanSet())
	}

	rp.Field(0).Elem().SetString("Brian")
	fmt.Println(*p.FirstName)

	// Yields nil pointer error
	// rp.Field(1).Elem().SetString("Johnson")
	// fmt.Println(*p.LastName)

	fmt.Println(rp.Field(1).Type())
	fmt.Println(rp.Field(1).CanSet())
	// fmt.Println(rp.Field(1).Elem().Type()) // nil pointer here also
	fmt.Println(rp.Field(1).Elem().CanSet())
}

在Golang Playground中查看:链接

英文:

Using Go's reflect package, is there a way to set a pointer in a struct if the pointer is nil? Looking at the reflect package, if reflect.Value.CanSet() is false then any Set() calls will yield a panic. Is there another way around this, only using the reflect package, not depending on any direct reference to the struct? For example, how can I set the empty last name as "Johnson" in the code below?

package main

import (
	&quot;fmt&quot;
    &quot;reflect&quot;
)

type Person struct {
    FirstName *string
	LastName  *string
}

func main() {
    p := Person{}
	firstName := &quot;Ryan&quot;
	p.FirstName = &amp;firstName

    rp := reflect.ValueOf(p)
	fmt.Println(&quot;rp:&quot;, rp)

    for i := 0; i &lt; rp.NumField(); i++ {
	    fmt.Printf(&quot;%s: Pointer: %d CanSet: %t\n&quot;, rp.Type().Field(i).Name, rp.Field(i).Pointer(), rp.Field(i).Elem().CanSet())
	}

    rp.Field(0).Elem().SetString(&quot;Brian&quot;)
	fmt.Println(*p.FirstName)

    // Yields nil pointer error
	// rp.Field(1).Elem().SetString(&quot;Johnson&quot;)
    // fmt.Println(*p.LastName)

	fmt.Println(rp.Field(1).Type())	
    fmt.Println(rp.Field(1).CanSet())
	// fmt.Println(rp.Field(1).Elem().Type()) // nil pointer here also
    fmt.Println(rp.Field(1).Elem().CanSet())
}

See in Golang Playground

答案1

得分: 11

你首先需要一个指向 Person{} 的指针,因为你需要给 LastName 字段设置一个值。

p := &Person{}

然后,你可以将一个有效的指针值设置给 LastName 字段,这将允许你设置字符串值:

rp.Field(1).Set(reflect.New(rp.Field(1).Type().Elem()))
rp.Field(1).Elem().SetString("Jones")

https://play.golang.org/p/f5MjpkDI2H

英文:

You first need a pointer to a Person{}, because you need to set a value to the LastName Field.

p := &amp;Person{}

Then you can set a valid pointer value to the LastName field, which will allow you to set the string value:

rp.Field(1).Set(reflect.New(rp.Field(1).Type().Elem()))
rp.Field(1).Elem().SetString(&quot;Jones&quot;)

https://play.golang.org/p/f5MjpkDI2H

huangapple
  • 本文由 发表于 2017年5月3日 01:51:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/43744238.html
匿名

发表评论

匿名网友

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

确定