2 回答
TA贡献1831条经验 获得超9个赞
发生错误是因为涉及类型参数的操作(包括赋值和返回)必须对其类型集中的所有类型都有效。在 的情况下string | int,没有从字符串初始化它们的值的通用操作。
但是,您仍然有几个选择:
类型切换T
您在类型切换中使用具有泛型类型的字段T,并将具有具体类型的值临时设置为interface{}/ any。然后类型断言接口返回T以返回它。请注意,此断言是未经检查的,因此如果出于某种原因ret持有不在T. 当然你可以用 comma-ok 检查它,但它仍然是一个运行时断言:
func (f *Field[T]) Get() (T, error) {
value, ok := os.LookupEnv(f.name)
if !ok {
return f.defaultValue, nil
}
var ret any
switch any(f.defaultValue).(type) {
case string:
ret = value
case int:
// don't actually ignore errors
i, _ := strconv.ParseInt(value, 10, 64)
ret = int(i)
}
return ret.(T), nil
}
类型切换*T
您可以进一步简化上面的代码并摆脱空接口。在这种情况下,您获取T-type 变量的地址并打开指针类型。这是在编译时完全类型检查的:
func (f *Field[T]) Get() (T, error) {
value, ok := env[f.name]
if !ok {
return f.defaultValue, nil
}
var ret T
switch p := any(&ret).(type) {
case *string:
*p = value
case *int:
i, _ := strconv.ParseInt(value, 10, 64)
*p = int(i)
}
// ret has the zero value if no case matches
return ret, nil
}
请注意,在这两种情况下,您都必须将T值转换为interface{}/any才能在类型开关中使用它。您不能直接在T.
带地图模拟的游乐场os.LookupEnv:https ://go.dev/play/p/LHqizyNL9lP
TA贡献1951条经验 获得超3个赞
好的,如果使用反射,类型开关可以工作。
func (f *Field[T]) Get() (T, error) {
raw, ok := os.LookupEnv(f.name)
if !ok {
return f.defaultValue, nil
}
v := reflect.ValueOf(new(T))
switch v.Type().Elem().Kind() {
case reflect.String:
v.Elem().Set(reflect.ValueOf(raw))
case reflect.Int:
value, err := strconv.ParseInt(raw, 10, 64)
if err != nil {
return f.defaultValue, err
}
v.Elem().Set(reflect.ValueOf(int(value)))
}
return v.Elem().Interface().(T), nil
}
但是非常欢迎更好的解决方案;-)
- 2 回答
- 0 关注
- 84 浏览
添加回答
举报