Мне интересно , почему Go does't неявно преобразовать []T
в []interface{}
когда он будет неявно преобразовать T
в interface{}
. Есть ли что-то нетривиальное в этом преобразовании, которое я пропускаю?
Пример:
func foo([]interface{}) { /* do something */ }
func main() {
var a []string = []string{"hello", "world"}
foo(a)
}
go build
жалуется
нельзя использовать (строку типа []) как интерфейс типа [] {} в аргументе функции
И если я попытаюсь сделать это явно, то же самое: b := []interface{}(a)
жалуется
невозможно преобразовать (строку типа []) в интерфейс типа [] {}
Таким образом, каждый раз, когда мне нужно сделать это преобразование (которое, кажется, очень много), я делал что-то вроде этого:
b = make([]interface{}, len(a), len(a))
for i := range a {
b[i] = a[i]
}
Есть ли лучший способ сделать это, или стандартные функции библиотеки, чтобы помочь с этими преобразованиями? Кажется глупым писать 4 дополнительные строки кода каждый раз, когда я хочу вызвать функцию, которая может принимать список, например, целые числа или строки.
источник
Ответы:
В Go существует общее правило, согласно которому синтаксис не должен скрывать сложные / дорогостоящие операции. Преобразование
string
вinterface{}
делается в O (1) времени. Преобразование[]string
вinterface{}
также делается в O (1) времени , так как кусочек еще одно значение. Однако преобразование a[]string
в a -[]interface{}
это O (n), потому что каждый элемент среза должен быть преобразован в ainterface{}
.Единственным исключением из этого правила является преобразование строк. При преобразовании
string
в и из a[]byte
или a[]rune
Go выполняет O (n), даже если преобразования являются «синтаксисом».Не существует стандартной библиотечной функции, которая сделает это преобразование за вас. Вы можете сделать один с отражением, но это будет медленнее, чем трехстрочный вариант.
Пример с отражением:
Ваш лучший вариант - использовать строки кода, которые вы задали в своем вопросе:
источник
map
S слишком кстати.channels
.Converting a []string to an interface{} is also done in O(1) time
?То, что вам не хватает, - это то, что
T
иinterface{}
которое имеет значение,T
имеет различные представления в памяти, поэтому не может быть легко преобразовано.Переменная типа
T
- это просто ее значение в памяти. Информация о связанном типе отсутствует (в Go каждая переменная имеет один тип, известный во время компиляции, а не во время выполнения). В памяти это выглядит так:interface{}
Держит переменная типаT
представлена в памяти , как этоT
Итак, возвращаясь к вашему первоначальному вопросу: почему go не конвертируется
[]T
в явном виде[]interface{}
?Преобразование
[]T
в[]interface{}
будет включать создание нового срезаinterface {}
значений, что является нетривиальной операцией, поскольку макет в памяти совершенно другой.источник
Вот официальное объяснение: https://github.com/golang/go/wiki/InterfaceSlice
источник
[]interface
на тип, который я ожидаю, например[]map[string]interface{}
?Попробуй
interface{}
вместо этого. Чтобы отбросить как кусочек, попробуйтеисточник
bar
чтобы интерпретировать его как «фрагмент любого типа»? Обратите внимание, что его три лайнера создает, а[]interface{}
не[]string
или кусок другого конкретного типа.func foo(bar []string) { /* ... */ }
interface{}
заставит компилятор не жаловаться при передаче аргумента как вfoo(a)
. Он мог использовать рефлекс или переключение типов ( golang.org/doc/effective_go.html#type_switch ) внутриfoo
.Конвертировать
interface{}
в любой тип.Синтаксис:
Пример:
источник
invalid type assertion: potato.([]string) (non-interface type []interface {} on left)
Если вам нужно более короткое замыкание кода, вы можете создать новый тип для помощника
затем
источник