Golang中reflect.Value.Set使用不可寻址值的解决方法

Golang中reflect.Value.Set使用不可寻址值的解决方法 我正在尝试创建一个 struct 并为其附加 字段方法/函数,因此我以以下代码开始:

package main

import (
	"reflect"
)

func main() {
	s := reflect.Zero(reflect.TypeOf(reflect.Struct))
	f := reflect.Zero(reflect.TypeOf(reflect.StructField{
		Name:      "id",
		PkgPath:   "",
		Type:      reflect.TypeOf(reflect.Int),
		Tag:       "",
		Offset:    0,
		Index:     []int{},
		Anonymous: false,
	}))

	m := reflect.Zero(reflect.TypeOf(reflect.Method{
		Name:    "add",
		PkgPath: "",
		Type: reflect.TypeOf(reflect.FuncOf(
			[]reflect.Type{reflect.TypeOf(reflect.Int)},
			[]reflect.Type{reflect.TypeOf(reflect.Int)},
			false)),
		Func:  f,
		Index: 0,
	}))

	swap := func(in []reflect.Value) []reflect.Value {
		return []reflect.Value{in[1], in[0]}
	}

	t := reflect.ValueOf(&swap).Elem()
	m.Set(reflect.MakeFunc(t.Type(), swap))
	_ = m
	_ = s

}

但在 m.Set(reflect.MakeFunc(t.Type(), swap)) 这一行,我遇到了错误:

panic: reflect: reflect.Value.Set using unaddressable value

goroutine 1 [running]:
reflect.flag.mustBeAssignableSlow(0x3?)
        D:/Development/go/src/reflect/value.go:262 +0x85
reflect.flag.mustBeAssignable(...)
        D:/Development/go/src/reflect/value.go:249
reflect.Value.Set({0xa7ff20?, 0xb53a60?, 0xa8c208?}, {0xa78500?, 0xc00008a210?, 0xa14313?})
        D:/Development/go/src/reflect/value.go:2084 +0x6a
main.main()
        D:/Deployment/Reflection/add.go:35 +0x3cf
exit status 2

更多关于Golang中reflect.Value.Set使用不可寻址值的解决方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

遗憾的是,您无法在运行时为类型生成方法,但可以生成不带方法的结构体,然后使用其他反射函数(如 MakeFunc)来创建操作这些结构体的函数:Go Playground - The Go Programming Language

func main() {
    fmt.Println("hello world")
}

更多关于Golang中reflect.Value.Set使用不可寻址值的解决方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我将为您指出您本应能够找到的文档。您不能那样做。请将 m 初始化为您希望它拥有的值。

favicon.ico

reflect package - reflect - Go Packages

Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types.

favicon.ico

reflect package - reflect - Go Packages

Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types.

favicon.ico

reflect package - reflect - Go Packages

Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types.

如果您计划使用反射,您应该非常熟悉以下内容:

The Laws of Reflection - The Go Programming Language

gopher5logo.jpg

How reflections works in Go, how to think about it, and how to use it.

这是一个典型的反射中使用不可寻址值的问题。reflect.Zero() 返回的是不可寻址的值,而 Set() 方法要求目标值必须是可寻址的。

以下是修正后的代码示例:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	// 创建结构体类型
	structType := reflect.StructOf([]reflect.StructField{
		{
			Name: "Id",
			Type: reflect.TypeOf(0),
		},
	})

	// 创建结构体实例(可寻址)
	s := reflect.New(structType).Elem()
	s.Field(0).SetInt(42)

	// 创建方法类型
	methodType := reflect.FuncOf(
		[]reflect.Type{reflect.TypeOf(0)},
		[]reflect.Type{reflect.TypeOf(0)},
		false,
	)

	// 创建方法值(可寻址)
	m := reflect.New(methodType).Elem()

	// 创建函数实现
	swap := func(in []reflect.Value) []reflect.Value {
		return []reflect.Value{reflect.ValueOf(in[0].Int() + 1)}
	}

	// 设置方法值
	m.Set(reflect.MakeFunc(methodType, swap))

	// 测试方法调用
	result := m.Call([]reflect.Value{reflect.ValueOf(10)})
	fmt.Println("Result:", result[0].Int()) // 输出: Result: 11

	// 如果需要将方法附加到结构体,可以使用接口
	var iface interface{} = struct{}{}
	val := reflect.ValueOf(&iface).Elem()
	
	// 创建包含方法的接口类型
	interfaceType := reflect.TypeOf((*interface {
		Add(int) int
	})(nil)).Elem()
	
	// 实现接口
	proxy := reflect.MakeFunc(
		interfaceType.Method(0).Type,
		func(args []reflect.Value) []reflect.Value {
			return []reflect.Value{reflect.ValueOf(args[0].Int() + 1)}
		},
	)
	
	// 创建实现接口的值
	impl := reflect.New(interfaceType).Elem()
	impl.Set(proxy)
	
	// 调用接口方法
	callResult := impl.Method(0).Call([]reflect.Value{reflect.ValueOf(5)})
	fmt.Println("Interface result:", callResult[0].Int()) // 输出: Interface result: 6
}

关键修改点:

  1. 使用 reflect.New() 创建可寻址的值而不是 reflect.Zero()
  2. reflect.New() 返回的是指针,需要调用 .Elem() 获取底层值
  3. 对于方法设置,使用 reflect.MakeFunc() 创建函数值
  4. 结构体字段和方法需要通过正确的类型定义来创建

如果需要动态创建包含方法的结构体,更常见的做法是:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	// 定义结构体类型
	structType := reflect.StructOf([]reflect.StructField{
		{
			Name: "Value",
			Type: reflect.TypeOf(0),
		},
	})

	// 创建实例
	instance := reflect.New(structType).Elem()
	instance.Field(0).SetInt(100)

	// 创建方法
	methodType := reflect.FuncOf(
		[]reflect.Type{reflect.TypeOf(0)},
		[]reflect.Type{reflect.TypeOf(0)},
		false,
	)

	method := reflect.MakeFunc(methodType, func(args []reflect.Value) []reflect.Value {
		current := instance.Field(0).Int()
		newValue := current + args[0].Int()
		instance.Field(0).SetInt(newValue)
		return []reflect.Value{reflect.ValueOf(newValue)}
	})

	// 使用方法
	result := method.Call([]reflect.Value{reflect.ValueOf(50)})
	fmt.Println("Method result:", result[0].Int()) // 输出: Method result: 150
	fmt.Println("Instance value:", instance.Field(0).Int()) // 输出: Instance value: 150
}

这样就能正确创建可寻址的值并进行设置了。

回到顶部