給定以下代碼...
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
}
編譯器顯示錯誤:
field.go:37:9: cannot use value (variable of type string) as type T in return statement
有沒有辦法為所有可能FieldType的 s 提供實作?
喜歡...
func (f *Field[string]) Get() (string, error) {
value, ok := os.LookupEnv(f.name)
if !ok {
return f.defaultValue, nil
}
return value, nil
}
func (f *Field[int]) Get() (int, error) {
raw, ok := os.LookupEnv(f.name)
if !ok {
return f.defaultValue, nil
}
value, err := strconv.ParseInt(raw, 10, 64)
if err != nil {
return *new(T), err
}
return int(value), nil
}
歡迎任何提示。
uj5u.com熱心網友回復:
這似乎不是泛型的作業,因為您仍然需要針對每種不同型別的特定代碼。當您的泛型代碼在所有受T.
對于預先宣告的型別string和int,沒有一個通用的操作可以從字串初始化它們的值。然而...
有沒有辦法為所有可能的 FieldTypes 提供實作?
我能想到的最簡潔的解決方案是在 type 上使用型別開關T。Field您可以利用struct 已經具有defaultValuetype欄位的事實T:
func (f *Field[T]) Get() (T, error) {
value, ok := os.LookupEnv(f.name)
if !ok {
return f.defaultValue, nil
}
var ret interface{}
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
}
筆記:
- 您必須轉換
defaultValue為interface{}/any才能在型別開關中使用它。您不能直接在 type 上進行型別切換T。 - 您仍然必須將
interface{}其用作變數來臨時保存回傳值。T僅當給定的具體型別可分配給 的型別集中的每個特定型別時,才允許分配toT。 - 您在回傳時鍵入斷言
ret.(T)(記住那ret是一個interface{},不是T)。注意這個斷言是未經檢查的,所以如果由于某種原因ret持有不在型別集中的東西,它可能會恐慌T
帶有要模擬的地圖的 GoTip 游樂場os.LookupEnv:https ://gotipplay.golang.org/p/gK9W3AicfMt
uj5u.com熱心網友回復:
好的,如果使用反射,型別開關可以作業。
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
}
但是非常歡迎更好的解決方案;-)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/426101.html
上一篇:這兩種通用方法有什么區別?
