2 回答

TA貢獻(xiàn)1831條經(jīng)驗 獲得超9個贊
發(fā)生錯誤是因為涉及類型參數(shù)的操作(包括賦值和返回)必須對其類型集中的所有類型都有效。在 的情況下string | int,沒有從字符串初始化它們的值的通用操作。
但是,您仍然有幾個選擇:
類型切換T
您在類型切換中使用具有泛型類型的字段T,并將具有具體類型的值臨時設(shè)置為interface{}/ any。然后類型斷言接口返回T以返回它。請注意,此斷言是未經(jīng)檢查的,因此如果出于某種原因ret持有不在T. 當(dāng)然你可以用 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值轉(zhuǎn)換為interface{}/any才能在類型開關(guān)中使用它。您不能直接在T.
帶地圖模擬的游樂場os.LookupEnv:https ://go.dev/play/p/LHqizyNL9lP

TA貢獻(xiàn)1951條經(jīng)驗 獲得超3個贊
好的,如果使用反射,類型開關(guān)可以工作。
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 關(guān)注
- 117 瀏覽
添加回答
舉報