Вариантные общие аргументы в Go
Допустим, я хочу сделать эквивалент JavaScriptArray.splice
Функция в Go, для ломтиков. У меня есть следующий код:
func splice(slice []int, index, amount int, elements ...int) []int {
newslice := make([]int, 0)
for i := 0; i < index; i++ {
newslice = append(newslice, slice[i])
}
for i := index + amount; i < len(slice); i++ {
newslice = append(newslice, slice[i])
}
for _, el := range elements {
newslice = append(newslice, el)
}
return newslice
}
Этот пример будет работать, но только для аргументов типа int
, Я хочу сделать это общим, и я знаю, что я должен дать аргумент elements
тип interface{}
, но как мне создать новый фрагмент с типом этого интерфейса внутри функции?
Другими словами, как я могу динамически указывать тип среза в зависимости от типа аргументов в первой строке функции, где newslice
создано?
2 ответа
Вместо того, чтобы эмулировать JavaScript в Go (почему???), я хотел бы предложить составить схожие простые операции из строительных блоков SliceTricks.
Они есть:
- Полностью введите агностик (подумайте "дженерики" бесплатно).
- Довольно вероятно, довольно быстро по сравнению с упаковкой / распаковкой чего-либо в / из
[]interface{}
,
Используя отражение
Если вы действительно хотите делать что-то общее, рефлексия является окончательным ответом. См. Документацию MakeSlice в пакете отражения для получения подробной информации о вашей проблеме.
Вам просто нужно получить тип входящего среза (используя TypeOf(...)
) и применение MakeSlice
правильно.
Пример использования отражения для создания среза:
y := []int{1,2,3}
t := reflect.TypeOf(y)
slice := reflect.MakeSlice(t, 0, 10)
slice = reflect.Append(slice, reflect.ValueOf(2))
fmt.Println(slice.Interface())
С помощью []interface{}
Еще один способ работы с []interface{}
, который может хранить любое значение, но может привести к панике во время выполнения, поскольку вы полностью пропускаете проверку типов компилятора (это плохо).
Вот пример использования []interface{}
в качестве хранилища для произвольных значений. При этом вам не нужно знать тип в вашей соединительной реализации, вы просто соединяете и используете []interface{}
для новых ломтиков.
Недостатком этого метода является то, что вы не можете преобразовать часть в []interface{}
без труда. Вы должны скопировать его вручную, как описано в постах ранее.
Заключение
Независимо от того, какую версию вы используете, вы никогда не получите обратно безопасность типов, не зная тип и не преобразовав его обратно вручную. В Go нет такой вещи, которая сделает это за вас. Это означает, что в вашем коде будет что-то подобное для восстановления безопасности типов:
x := []int{1,2,3,4}
y := splice(x, ...)
yn := []int(y)