2 回答

TA貢獻1811條經驗 獲得超5個贊
簡短的回答?你不能。
長答案,你仍然不能直接這樣做,但是:
func removeFrom(slice interface{}, index int) interface{} {
switch slice := slice.(type) {
case []float64:
if len(slice) > index {
return append(slice[:index], slice[index+1:]...)
}
case []int64:
if len(slice) > index {
return append(slice[:index], slice[index+1:]...)
}
case []int:
if len(slice) > index {
return append(slice[:index], slice[index+1:]...)
}
default:
log.Panicf("unknown type: %T", slice)
}
}

TA貢獻1111條經驗 獲得超0個贊
Go 不支持泛型,所有切片類型都沒有“共同祖先”(例如,[]interface{}與“不兼容” []int,請參閱無法將 []string 轉換為 []interface {}了解更多詳細信息)。
因此,如果您希望您的函數接受任何切片類型,則必須使用interface{}(對于“傳入”參數和返回類型)。但是現在您有一個(接口)包裝器值,您不能對其應用切片,也不能將其傳遞給內置append()函數。
您可以對已知類型使用類型斷言和類型開關,但是您必須為每個類型重復代碼,所以這并不是真正的領先一步。
實際上,有一種方法可以removeFrom()使用反射創建一個適用于所有切片類型的函數。
reflect.Value是一種描述任何 Go 值的類型。它為不同類型的 Go 值提供支持方法,包括切片。
我們感興趣的是Value.Slice()方法:
func (v Value) Slice(i, j int) Value
我們可以用它來切片。好的。這是我們的元素去除算法中的一個關鍵點。仍然需要“加入”2 個切片,即可移動元素之前的切片和可移動元素之后的切片。幸運的是,這個reflect包也支持這個reflect.AppendSlice()::
func AppendSlice(s, t Value) Value
作為最后剩下的鍵,我們可以Value.Len()用來獲取任何切片的長度。
我們現在擁有了我們的一般removeFrom()功能所需的一切,這非常簡單:
func removeFrom(s interface{}, idx int) interface{} {
if v := reflect.ValueOf(s); v.Len() > idx {
return reflect.AppendSlice(v.Slice(0, idx), v.Slice(idx+1, v.Len())).Interface()
}
return s
}
真的,僅此而已。測試它:
for i := 0; i < 4; i++ {
fmt.Println(removeFrom([]int{0, 1, 2}, i), "missing:", i)
}
for i := 0; i < 4; i++ {
fmt.Println(removeFrom([]string{"zero", "one", "two"}, i), "missing:", i)
}
輸出(在Go Playground上試試):
[1 2] missing: 0
[0 2] missing: 1
[0 1] missing: 2
[0 1 2] missing: 3
[one two] missing: 0
[zero two] missing: 1
[zero one] missing: 2
[zero one two] missing: 3
筆記:
該解決方案使用反射,因此它比不使用反射但具有“連接”的具體支持類型的另一個解決方案要慢。快速基準測試表明,這種通用解決方案比有線輸入類型的非反射慢 2.5 倍。應該權衡性能或便利性/通用解決方案是否更重要?;蛘吣憧梢詫⑺c具體類型結合起來:你可以添加一個類型開關來處理頻繁的類型,并且只有在類型開關沒有處理實際的具體類型時才恢復到這個通用解決方案。
- 2 回答
- 0 關注
- 146 瀏覽
添加回答
舉報