gpt4 book ai didi

go - 通过反射将 *struct 归零(不知道底层类型)并将指针重新分配给接口(interface)

转载 作者:IT王子 更新时间:2023-10-29 02:10:09 26 4
gpt4 key购买 nike

背景

我正在构建一个包装程序包,它组合了定义的命令并允许它们在 cli 或交互式 shell 上下文中执行。命令在类似这样的结构中定义(显示相关字段):

type Handler func(c *Command) error

type Command struct {
RequestHandler Handler
ResponseHandler Handler
Request interface{} //pointer to struct
Response interface{} //pointer to struct
}

底层请求/响应对象始终是指向结构的指针,因此我大量使用反射来递归迭代底层结构字段,以根据调用上下文 (shell/cli) 将它们的字段显示为标志或提示。然后,我根据用户输入使用反射填充请求对象。

到目前为止,还不错......

问题

当我在交互式 shell 上下文中时,可能会调用一个命令并填充请求结构及其值 - 一切正常。但是,如果再次调用该命令,请求仍然存在(响应也可能存在),所以我希望在命令上实现一个“重置”方法,当从 shell 调用命令时可以在内部调用该方法。

现在正如我所说,我可以保证请求和响应都是指向结构的指针。但是当我只有一个接口(interface)并且对底层类型没有高级知识((并且内部字段可能是结构值)时,我如何将它们设置回各自的初始化 nil 值。

可能的方法

  1. 在命令注册时(填充之前)添加底层请求/响应对象的第二个副本,然后在重置时复制它

  2. 只需创建一个通用的重置结构函数,该函数作用于底层结构指针的任何接口(interface)

  3. 我不知道哪个方法对我有用

我都试过了,但我正在努力实现其中一个

方法一:

type Command struct {
RequestHandler Handler
ResponseHandler Handler
zeroRequest interface{}
zeroResponse interface{}
Request interface{} //pointer to struct
Response interface{} //pointer to struct
}

func (c *Command) register() error {
// validate is pointer
reqPtrVal := reflect.ValueOf(c.Request)
if reqPtrVal.Kind() != reflect.Ptr {
return ErrStructPtrExpected
}

// reflect the underlying value and validate is struct
reqVal := reflect.Indirect(reqPtrVal)
if reqVal.Kind() != reflect.Struct {
return ErrStructPtrExpected
}

c.zeroRequest = reqVal.Interface()

// other logic...
}

func (c *Command) handleShell(sc *ishell.Context) {
// reset request / response objects

// reflect the underlying zero value and validate is struct
reqVal := reflect.ValueOf(c.zeroRequest)
if reqVal.Kind() != reflect.Struct {
c.Commander.HandleError(ErrStructPtrExpected)
}

newRequest := reflect.New(reqVal.Type())

// unfortunately below doesn't work as newRequest.CanAddr() == false
c.zeroRequest = newRequest.Addr().Interface()

// other logic
}

方法 2:这感觉有点干净(没有零值副本/更少的代码),但我什至无法使用这种方法进行编译:

func (c *Command) resetStruct(structPtr interface{}) error {
// validate is pointer
ptrVal := reflect.ValueOf(structPtr)
if ptrVal.Kind() != reflect.Ptr {
return ErrStructPtrExpected
}

// reflect the underlying value and validate is struct
val := reflect.Indirect(ptrVal)
if val.Kind() != reflect.Struct {
return ErrStructPtrExpected
}

// create a new val from the underlying type and reassign the pointer
newVal := reflect.New(val.Type())
ptrVal.SetPointer(newVal.Addr())
return nil
}

总结

最终目标是通过反射将这个未知类型的结构归零,并将指针重新分配回请求接口(interface)。首选的方法顺序是 3、2、1 - 但任何可行的方法都只是花花公子。

如果我可以从 reflect.Type 创建一个具体类型,我似乎可以解决这个问题,但也许这里还有另一种方法

最佳答案

您可以使用 reflect.Zeroreflect.New 请检查下面的代码片段以确保清晰度

这里是你如何使用它

package main

import (
"fmt"
"reflect"
)

type A struct {
B int
}

func reset(p interface{}) interface{} {
var isPtr bool
v := reflect.ValueOf(p)
for v.Kind() == reflect.Ptr {
isPtr = true
v = v.Elem()
}
if isPtr {
return reflect.New(v.Type()).Interface()

}

return reflect.Zero(v.Type()).Interface()

}

func main() {
p := A{1}
fmt.Printf("Original : %+v,Pointer : %+v,Value : %+v", p, reset(&p), reset(p))
}

播放:https://play.golang.com/p/8CJHHBL6c2p

关于go - 通过反射将 *struct 归零(不知道底层类型)并将指针重新分配给接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49151893/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com