1 回答
TA贡献1963条经验 获得超6个赞
实际上,您问题中显示的代码除了将类型传递给错误并设置错误格式外,什么也没做json.Unmarshal,因此您可以重写函数以使其表现得像它一样:
func LoadConfiguration(data []byte) (*Type1, error) {
config := &Type1{}
if err := loadConf(data, config); err != nil {
return nil, err
}
// ...
}
// "magically" accepts any type
// you could actually get rid of the intermediate function altogether
func loadConf(bytes []byte, config any) error {
if err := json.Unmarshal(bytes, config); err != nil {
return fmt.Errorf("cannot load config: %v", err)
}
return nil
}
如果代码实际上做的不仅仅是将指针传递给json.Unmarshal,它可以从类型参数中获益。
type Configurations interface {
Type1 | Type2
}
func loadConf[T Configurations](bytes []byte) (*T, error) {
config := new(T)
if err := json.Unmarshal(bytes, config); err != nil {
return nil, fmt.Errorf("cannot load config: %v", err)
}
return config, nil
}
func loadConfOther[T Configurations]() (*T, error) {
flatconfig := new(T)
// ... code
return flatconfig, nil
}
在这些情况下,您可以创建一个任一类型的新指针,new(T)然后json.Unmarshal负责将字节切片或文件的内容反序列化到其中——前提是 JSON 实际上可以解组到任一结构中。
顶层函数中的特定于类型的代码应该仍然不同,特别是因为您想要使用显式具体类型实例化通用函数。所以我建议保留LoadConfiguration1and LoadConfiguration2。
func LoadConfiguration1(data []byte) (*Type1, error) {
config, err := loadConf[Type1](data)
if err != nil {
return nil, err
}
confOther, err := loadConfOther[Type1]()
if err != nil {
return nil, err
}
// ... type specific code
return config, nil
}
但是,如果特定于类型的代码只是其中的一小部分,您可能可以为特定部分使用类型切换,尽管在您的情况下这似乎不是一个可行的选择。我看起来像:
func LoadConfiguration[T Configuration](data []byte) (*T, error) {
config, err := loadConf[T](data)
if err != nil {
return nil, err
}
// let's pretend there's only one value of type parameter type
// type-specific code
switch t := config.(type) {
case *Type1:
// ... some *Type1 specific code
case *Type2:
// ... some *Type2 specific code
default:
// can't really happen because T is restricted to Configuration but helps catch errors if you extend the union and forget to add a corresponding case
panic("invalid type")
}
return config, nil
}
最小的游乐场示例:https ://go.dev/play/p/-rhIgoxINTZ
- 1 回答
- 0 关注
- 101 浏览
添加回答
举报