你可以使用Go的反射(reflect)包来设置结构体指针的值。

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

GO: how can i use go reflect to set the value of pointer of struct

问题

package main

import (
	"fmt"
	"reflect"
)

type Config struct {
	App *AppConfig
}

type AppConfig struct {
	Name string
}

func (a *AppConfig) Parse() {
	a.Name = "111"
}

var (
	config = &Config{
		App: &AppConfig{},
	}
)

func main() {

	v := reflect.ValueOf(*config)
	typeOf := reflect.TypeOf(*config)

	for i := 0; i < typeOf.NumField(); i++ {
		method := v.Field(i).MethodByName("Parse")
		method.Call([]reflect.Value{})
	}
	fmt.Println(config)
}

看这个,它可以成功运行。

但是当我将

var (
	config = &Config{
		App: &AppConfig{},
	}
)

改为

var (
	config = &Config{}
)

它会失败,并显示错误信息:#panic: runtime error: invalid memory address or nil pointer dereference#

我该如何使其成功运行?

英文:
package main

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

type Config struct {
	App *AppConfig
}

type AppConfig struct {
	Name string
}

func (a *AppConfig) Parse() {
	a.Name = &quot;111&quot;
}

var (
	config = &amp;Config{
		App: &amp;AppConfig{},
	}
)

func main() {

	v := reflect.ValueOf(*config)
	typeOf := reflect.TypeOf(*config)

	for i := 0; i &lt; typeOf.NumField(); i++ {
		method := v.Field(i).MethodByName(&quot;Parse&quot;)
		method.Call([]reflect.Value{})
	}
	fmt.Println(config)
}

look at this, it can run successfully

but when i change

var (
	config = &amp;Config{
		App: &amp;AppConfig{},
	}
)

to

var (
	config = &amp;Config{}
)

it will be failed with error #panic: runtime error: invalid memory address or nil pointer dereference#

how can i run successfully with

var (
	config = &amp;Config{}
)

答案1

得分: 1

给定 f := v.Field(i),其中 f 表示一个指针类型,你首先需要检查 f 表示的值是否不为 nil,在反射包中有一个方法可以做到这一点。如果返回的是 true,即它是 nil,那么在调用该字段的方法之前,你需要初始化该字段,使其不再是 nil。即 f.Set(reflect.New(f.Type().Elem()))

你还需要确保 f 是可寻址的,为此,将指向配置的指针传递给反射,即 *Config,而不是 Config

v := reflect.ValueOf(config).Elem()
typeOf := reflect.TypeOf(config).Elem()

for i := 0; i < typeOf.NumField(); i++ {
	f := v.Field(i)
	if f.Kind() == reflect.Ptr && f.IsNil() {
		f.Set(reflect.New(f.Type().Elem()))
	}
	method := f.MethodByName("Parse")
	method.Call([]reflect.Value{})
}
fmt.Println(config)
fmt.Println(config.App)

https://go.dev/play/p/DMRFS41NXFS

英文:

Given f := v.Field(i) where f represents a pointer type, you first need to check whether the value represented by f isn't nil, there's a method for that in the reflect package. And if you get back true, i.e. it is nil, then, before you can call a method on that field, you need to initialize that field so that is it not nil anymore. i.e. f.Set(reflect.New(f.Type().Elem())).

And you also need to make sure that the f is addressable, to do that, pass a pointer to the config to reflect, i.e. *Config, not Config.

v := reflect.ValueOf(config).Elem()
typeOf := reflect.TypeOf(config).Elem()

for i := 0; i &lt; typeOf.NumField(); i++ {
	f := v.Field(i)
	if f.Kind() == reflect.Ptr &amp;&amp; f.IsNil() {
		f.Set(reflect.New(f.Type().Elem()))
	}
	method := f.MethodByName(&quot;Parse&quot;)
	method.Call([]reflect.Value{})
}
fmt.Println(config)
fmt.Println(config.App)

https://go.dev/play/p/DMRFS41NXFS

huangapple
  • 本文由 发表于 2022年8月24日 23:42:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/73476068.html
匿名

发表评论

匿名网友

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

确定