如何让Auth泛型结构体的Marshal方法支持值或指针参数?
问题解决:Go泛型Auth结构体实现Marshal多参数类型兼容
核心问题拆解
你需要实现:
Marshal方法支持直接传入值类型(如字符串)或指针类型,无需额外取址操作Unmarshal方法仅接受指针类型,且避免因泛型参数类型导致的类型不匹配问题- 避免将泛型参数设为指针类型时,
Unmarshal出现双重指针的错误
最优解决方案:约束泛型参数为值类型+泛型方法兼容多参数
通过约束Auth的泛型参数为非指针类型,同时给Marshal方法添加泛型参数支持值/指针输入,彻底解决类型冲突问题。
修改后完整代码
// 定义非指针类型约束,覆盖常用基础类型与自定义结构体 type NonPointer interface { ~string | ~int | ~int64 | ~float64 | ~bool | ~struct{} } type Auth[A NonPointer] struct { // 保留原有结构体字段 } // Unmarshal 保持原有逻辑,参数*A为单指针,符合json.Unmarshal要求 func (a *Auth[A]) Unmarshal(b []byte, val *A) error { if err := json.Unmarshal(b, val); err != nil { return err } // 此处添加你的业务逻辑 return nil } // Marshal 使用泛型参数T,同时支持传入A类型的值或*A类型的指针 func (a *Auth[A]) Marshal[T A | *A](val T) ([]byte, error) { b, err := json.Marshal(val) if err != nil { return nil, err } // 此处添加你的业务逻辑 return b, nil }
调用示例
// 基础类型场景:直接传值,无需取址 a := &Auth[string]{} _, err := a.Marshal("val") // 自定义结构体场景:值/指针都可传入 type Temp struct { Name string } b := &Auth[Temp]{} _, err = b.Marshal(Temp{Name: "test"}) // 传值 t := Temp{Name: "demo"} _, err = b.Marshal(&t) // 传指针 // Unmarshal正常调用,传入单指针即可 var out Temp err = b.Unmarshal([]byte(`{"Name":"foo"}`), &out)
为什么之前的尝试会出错?
你将A设为指针类型(如Auth[*Temp])时,Unmarshal的参数val *A会变成**Temp(双重指针),而json.Unmarshal需要的是指向目标值的单指针,因此传入&out(**Temp)会导致类型不匹配。通过约束A为非指针类型,Unmarshal的参数*A始终是单指针,完全符合标准库要求。
兼容指针类型泛型参数的备选方案
如果确实需要让A支持指针类型,可以在Unmarshal中通过反射处理双重指针的情况(会引入少量运行时开销):
func (a *Auth[A]) Unmarshal(b []byte, val *A) error { target := any(val) // 检查是否为双重指针,若是则解引用一次 if vt := reflect.TypeOf(target); vt.Kind() == reflect.Ptr && vt.Elem().Kind() == reflect.Ptr { target = reflect.ValueOf(target).Elem().Interface() } if err := json.Unmarshal(b, target); err != nil { return err } return nil }
内容的提问来源于stack exchange,提问作者javascriptGivesMeAnxiety
相关产品推荐
相关产品推荐

