背景
我正在构建一个包装器包,它结合了已定义的命令,并允许它们在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
}
底层的Request / Response对象总是指向结构的指针,所以我非常大量地使用反射来递归迭代底层的结构字段,根据调用上下文(shell / cli)将它们的字段显示为标志或提示。然后,我根据用户输入使用反射填充请求对象。
到目前为止,非常好......
问题
当我在交互式shell上下文中时,可以调用一个命令,并填充请求结构及其值 - 一切都很好。但是,如果再次调用该命令,则仍会填充请求(并且响应可能也是如此),因此我希望实现“重置”功能。命令的方法,当从shell调用命令时可以在内部调用。
现在正如我所说,我可以保证请求和响应都是指向结构的指针。但是当我所拥有的只是一个接口并且没有基础类型的高级知识((和内部字段可能是结构值)时,如何将它们设置回各自初始化的nil值。
可能的方法
在命令注册时(在填充之前)添加底层请求/响应对象的第二个副本,然后在重置时将其复制
只需创建一个通用的重置结构函数,该函数作用于基础结构指针的任何接口
某些方法我不知道这对我来说是什么
我已经尝试了两种方式,而且我正在努力实施
接近1:
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
}
摘要
最终目标是通过反射将这个未知类型的结构归零,并将指针重新分配回请求接口。接近的优先顺序是3,2,1 - 但任何有效的方法都只是花花公子。
似乎我可以解决这个问题,如果我可以从reflect.Type创建一个具体的类型,但也许这里有另一种方法
答案 0 :(得分:1)
您可以使用keyval = data.frame(GroupID = c('Group 1', 'Group 1', 'Group 1', 'Group 2', 'Group 2'),
Major.sectors = c('Food, beverages, tobacco', 'Publishing, printing',
'Other services', 'Construction',
'Machinery, equipment, furniture, recycling'), stringsAsFactors = FALSE)
left_join(df1, keyval) %>%
head
# Major.sectors EBIT.CAP GroupID
#1 Food, beverages, tobacco -0.29998599 Group 1
#2 Machinery, equipment, furniture, recycling -10.11204781 Group 2
#3 Construction -0.05840266 Group 2
#4 Publishing, printing 1.56335275 Group 1
#5 Other services -1.87696308 Group 1
#6 Hotels & restaurants -0.93189920 <NA>
或reflect.Zero
,请查看下面的代码段以获得清晰度
以下是如何使用它
reflect.New