2013-02-28 1 views
1

Я пытался реализовать функцию, которая может случайным образом выбрать элемент из любого типа среза (например, функции random.choice питона) пытается использовать интерфейс {} срезу, чтобы выбрать случайный элемент

func RandomChoice(a []interface{}, r *rand.Rand) interface{} { 
    i := r.Int()%len(a) 
    return a[i] 
} 

Однако при попытке передать в ломтике типа [] float32 в первый аргумент этой ошибка возникает:

cannot use my_array (type []float32) as type []interface {} in function argument

является ли это fundemental злоупотребления интерфейса {}? есть ли лучший способ сделать это?

ответ

0

Ну, я с трудом верю после всех поисков, что первый связанный с этим вопрос был: Type converting slices of interfaces in go который в значительной степени содержит ответ. Изменения RandomChoice использовать функцию InterfaceSlice, описанную в ответе на этот вопрос урожайность вопроса:

func RandomChoice(slice interface{}, r *rand.Rand) interface{} { 
    islice := InterfaceSlice(slice) 
    i := r.Int()%len(islice) 
    return islice[i] 
} 

, хотя, по-видимому, этот ответ не очень хорошо функционирует, поскольку он требует всего куска, чтобы быть преобразованы в [] интерфейс {}. ..

1

от language specification:

Два типа либо одинаковыми или разными.

Два именованных типа идентичны, если их имена типов берутся из того же TypeSpec. Именованный и неназванный тип всегда разные. Два неназначенных типа идентичны, если соответствующие литералы типа идентичны, то есть, если они имеют одну и ту же литеральную структуру, а соответствующие компоненты имеют одинаковые типы. В деталях:

  • Два типа массива идентичны, если они имеют одинаковые типы элементов и та же длина массива.
  • Два типа срезов идентичны, если они имеют одинаковые типы элементов .
  • Два типа структуры идентичны, если они имеют одну и ту же последовательность полей, и если соответствующие поля имеют одинаковые имена и идентичные типы и идентичные теги. Два анонимных поля считаются одинаковыми с . Имена полей в нижнем регистре из разных пакетов: всегда разные.
  • Два типа указателей идентичны, если они имеют одинаковые базовые типы.
  • Два типа функций идентичны, если они имеют одинаковое количество параметров и значений результата, соответствующие параметры и типы результатов идентичны, и обе обе функции являются переменными или их нет. Параметр и имена результатов не обязательно должны совпадать.
  • Два типа интерфейса идентичны, если они имеют один и тот же набор методов с одинаковыми именами и идентичными типами функций. Нижний регистр имена методов из разных пакетов всегда разные. Порядок методов не имеет значения.
  • Два типа карт идентичны, если они имеют одинаковые ключи и типы значений.
  • Два типа каналов идентичны, если они имеют одинаковые типы значений и одинаковое направление.

А:

Значение х присваиваемые переменной типа Т ("х присваиваемые Т") в любом из этих случаев:

  • х годов тип идентичен T.
  • Тип x типа V и T имеют одинаковые базовые типы, и по крайней мере один из V или T не является именованным типом.
  • Т является тип интерфейса и х реализует Т.
  • х является двунаправленным значение канала, Т представляет собой тип канала, X Тип V и Т имеют одинаковые типы элементов, и по меньшей мере один из V или Т не именованный тип.
  • x - предопределенный идентификатор nil, а T - указатель, функция, срез, карта, канал или тип интерфейса.
  • х представляет собой константу нетипизированным представима значение типа T.

Любое значение может быть назначен на пустой идентификатор.

Комбинация этих двух результатов, которые вы не можете присвоить [] MyType для интерфейса [] {}.

+0

Спасибо за ваш ответ на часть моего вопроса. Мне также нравится цитата из Стивена по ссылке из моего ответа: «В Go существует общее правило, что синтаксис не должен скрывать сложные/дорогостоящие операции». – kellpossible

5

Re: есть ли лучший способ сделать это?

IMO есть. OP подход неэффективен WRT к простому:

var v []T 
... 

// Select a random element of 'v' 
e := v[r.Intn(len(v))] 
... 

Обратите внимание, что оба подхода будут паниковать для len(v) == 0 до предварительно проверить это не сделано.

+0

Спасибо за ответ! Хотя я не совсем уверен, что понимаю этот жаргон. Вы предполагаете, что было бы лучше не использовать функцию RandomChoice? – kellpossible

+2

Да, вот что я имею в виду. Нет типов преобразований/утверждений, статического типа проверено и более высокой производительности времени выполнения для записи около десятка символов в строке. Который, возможно, даже меньше набирает, чем 'e: = RandomChoice (a, r). (T)' в любом случае. – zzzz

2

Использование отражения:

func RandomChoice(slice interface{}, r *rand.Rand) interface{} { 
    x := reflect.ValueOf(slice) 
    return x.Index(r.Intn(x.Len())).Interface() 
}