Могу ли я ввести срез значений интерфейса?

Я пытаюсь ввести assert из []Node в []Symbol. В моем коде Symbol реализует интерфейс Node.

Вот некоторый окружающий код:

 43 func applyLambda(args []Node, env Env) Node {
 44     if len(args) > 2 {
 45         panic("invalid argument count")
 46     }
 47     fixed, rest := parseFormals(args.([]Symbol))
 48     return Func{
 49         Body: args[1],
 50         FixedVarNames: fixed,
 51         RestVarName: rest,
 52     }
 53 }

Вот ошибка, которую я получаю:

./builtins.go:47: invalid type assertion: args.([]Symbol) (non-interface type []Node on left)

Я уверен, что для этого есть веская причина. Как лучше поступить?


person Matt Joiner    schedule 07.05.2012    source источник


Ответы (2)


В поговорке x.(T) переменная x должна быть интерфейсного типа, т.к. только для переменных интерфейсного типа динамический тип не фиксирован. И хотя Node — это интерфейс, []Node — нет. Слайс — это отдельный, не интерфейсный тип. Так что просто не имеет смысла предполагать, что срез значений интерфейса тоже является интерфейсом.

Тип Node имеет четкое определение в вашем коде и, таким образом, является интерфейсом. Вы указали список методов для него. Тип []Node не такой. Какие методы он определяет?

Я понимаю, откуда вы пришли с этим. Это может быть полезным ярлыком, но просто не имеет смысла. Это как ожидать, что syms.Method() сработает, когда syms имеет тип []Symbol, а Method соответствует Symbol.

Замена строки 47 этим кодом делает то, что вы хотите:

symbols := make([]Symbol, len(args))
for i, arg := range args { symbols[i] = arg.(Symbol) }
fixed, rest := parseFormals(symbols)
person Mostafa    schedule 07.05.2012
comment
Я не согласен с вашим предложением. Так что просто не имеет смысла предполагать, что часть значений интерфейса тоже является интерфейсом. Преобразования - это преобразования, а интерфейсы - это интерфейсы. Это разные понятия (по крайней мере, в моем уме). Авторы Go могли решить поддерживать преобразования из []Node в []Symbol, но они этого не сделали, потому что это слишком дорого, а такие преобразования не являются общепринятым шаблоном программирования. Теоретически любое преобразование, которое не влечет за собой противоречия или проблемы, имеет смысл, но разработчики языка должны выбирать, какие преобразования использовать в языке. - person ; 07.05.2012
comment
Я не могу точно сказать, что думают по этому поводу авторы Go, но я все же думаю, что мое предположение верно. Вы правы в том, что это преобразование слишком дорого, но я не думаю, что это является причиной того, что это является незаконным. Как я уже сказал, в Go слайс — это тип. Вы можете сказать type Nodes []Node. Является ли Nodes типом интерфейса? Нет. Я вижу, что именно по этой причине мы не можем утверждать переменные типа []Node. Хотели бы вы провести это обсуждение в списке рассылки golang-nuts? - person Mostafa; 07.05.2012
comment
@Atom: вопрос не касается конверсий; он спрашивает об утверждениях типа - person newacct; 07.05.2012

Go не позволяет этого. Вам нужно преобразовать Node в Symbol по отдельности.

Причина, по которой это не разрешено, заключается в том, что []Node и []Symbol имеют разные представления, поэтому при преобразовании потребуется выделить память для []Symbol.

person Community    schedule 07.05.2012
comment
дело в том, что вопрос даже не в конверсии. он спрашивает об утверждении типа - person newacct; 07.05.2012
comment
Вы правы, мой ответ сбивает с толку. Я удалил последнее предложение из своего ответа. - person ; 07.05.2012