Вариантные общие аргументы в 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)
Другие вопросы по тегам