我的概念Context是可以容納任何結構的地圖。基本上,我想創建一個通用的 getter,可添加地“填充”目標介面(類似于 json 解碼的作業方式)。
這是我希望它如何作業的示例:
type Context map[string]interface{}
// Random struct that will be saved in the context
type Step struct {
Name string
}
func main() {
stepA := &Step{Name: "Cool Name"}
c := Context{}
c["stepA"] = stepA
var stepB *Step
err := c.Get("stepA", stepB)
if err != nil {
panic(err)
}
fmt.Println(stepB.Name) // Cool Name
stepB.Name = "CoolName2"
fmt.Println(stepA.Name) // I want to say: CoolName2
}
func (c Context) Get(stepId string, dest interface{}) error {
context, ok := c[stepId]
if !ok {
return nil
}
destinationValue := reflect.ValueOf(dest)
contextValue := reflect.ValueOf(context)
destinationValue.Set(contextValue) // Errors here
return nil
}
我傾向于使用反射,但也許我不需要它?- 所以對其他建議持開放態度(泛型除外,因為這會使其他問題復雜化)我收到以下錯誤:
panic: reflect: reflect.Value.Set using unaddressable value
你可以在這里測驗它。
uj5u.com熱心網友回復:
傳遞給 Get 的引數必須是指標型別,其元素型別與背景關系映射中的型別相同。因此,如果背景關系映射中的值是 type *Step,那么引數的型別必須是**Step。傳入的引數也不能是nil,它可以是指向的指標nil,但它本身不能nil。
所以在你的情況下,你應該這樣做:
var stepB *Step
err := c.Get("stepA", &stepB) // pass pointer-to-pointer
if err != nil {
panic(err)
}
方法,修正了Get一下:
func (c Context) Get(stepId string, dest interface{}) error {
context, ok := c[stepId]
if !ok {
return nil
}
dv := reflect.ValueOf(dest)
if dv.Kind() != reflect.Ptr || dv.IsNil() {
return errors.New("dest must be non-nil pointer")
}
dv = dv.Elem()
cv := reflect.ValueOf(context)
if dv.Type() != cv.Type() {
return errors.New("dest type does not match context value type")
}
dv.Set(cv)
return nil
}
https://go.dev/play/p/OECttqp1aVg
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/513870.html
標籤:去
