Phi*_*üll 12 generics go type-switch
换句话说,如何为联合类型集中的不同类型实现特定于类型的解决方案?
鉴于以下代码...
type FieldType interface {
string | int
}
type Field[T FieldType] struct {
name string
defaultValue T
}
func NewField[T FieldType](name string, defaultValue T) *Field[T] {
return &Field[T]{
name: name,
defaultValue: defaultValue,
}
}
func (f *Field[T]) Name() string {
return f.name
}
func (f *Field[T]) Get() (T, error) {
value, ok := os.LookupEnv(f.name)
if !ok {
return f.defaultValue, nil
}
return value, nil
}
Run Code Online (Sandbox Code Playgroud)
编译器显示错误:
field.go:37:9: cannot use value (variable of type string) as type T in return statement
Run Code Online (Sandbox Code Playgroud)
有没有办法为所有可能的 s 提供实现FieldType
?
喜欢...
field.go:37:9: cannot use value (variable of type string) as type T in return statement
Run Code Online (Sandbox Code Playgroud)
任何提示都会受到欢迎。
bla*_*een 27
发生该错误的原因是涉及类型参数的操作(包括赋值和返回)必须对其类型集中的所有类型都有效。对于string | int
,没有通用操作可以从字符串初始化它们的值。
但是,您仍然有几个选择:
T
T
您可以在类型开关中使用具有泛型类型的字段,并将具有具体类型的值临时设置到interface{}
/中any
。然后键入断言接口返回T
以返回它。请注意,此断言未经检查,因此如果由于某种原因ret
持有不属于 类型集中的内容,它可能会出现恐慌T
。当然你可以用逗号-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
}
Run Code Online (Sandbox Code Playgroud)
*T
您可以进一步简化上面的代码并摆脱空接口。在这种情况下,您获取 -type 变量的地址T
并打开指针类型。这是在编译时进行完全类型检查的:
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
}
Run Code Online (Sandbox Code Playgroud)
请注意,在这两种情况下,您必须将T
值转换为interface{}
/any
才能在类型开关中使用它。您不能直接在 上进行类型切换T
。
带有模拟地图的游乐场os.LookupEnv
:https://go.dev/play/p/JVBEZwCXRMW
归档时间: |
|
查看次数: |
9025 次 |
最近记录: |