Странно рубиновое поведение

Мне нужно проверить, является ли переменная массивом, и если нет, преобразовать ее в единицу, прежде чем приступить к дальнейшей обработке. Итак, мой код выглядит так:

class Test < Struct.new(:args)
    def eval
        p "1. #{args}"
        args = (args.instance_of? Array) ? args : [args]
        p "2. #{args}" # woah! [nil]?
        # ...other things, with "args" being an array for sure..or not?!?
    end
end

Я совсем новичок в ruby, так что, возможно, это не очень идиоматично, но мне кажется, что этот код должен по крайней мере работать. Вместо этого во второй раз я печатаю args переменная, это [nil], Обратите внимание, что если я изменю метод eval немного:

def eval
    p "1. #{args}"
    a = args
    args = (a.instance_of? Array) ? a : [a]
    p "2. #{args}"
end

все работает как положено. Итак, есть что-то очень специфичное для класса Struct, которого я не понимаю, или что-то подозрительное происходит здесь? (используя ruby ​​1.9.3-dev на macosx, используя rvm)

1 ответ

Решение

На самом деле есть идиома Ruby для того, что вы пытаетесь сделать: [*args], * в этом контексте называется оператором сплат:

http://raflabs.com/blogs/silence-is-foo/2010/08/07/ruby-idioms-what-is-the-splatunary-operator-useful-for/

Если вы передадите массив, splat "сведет" массив в новый, если вы передадите один аргумент, он станет массивом из одного элемента.

Для странного поведения: мне кажется, что вы создаете локальную переменную args в вашем eval метод, который инициализируется nil потому что это на LHS задания. Тогда троичный оценивается как ложный, потому что args не является массивом и создает массив из текущего значения, которое по-прежнему nil, Если args будет переменная экземпляра (@args), все будет работать так, как вы ожидаете. Другими словами, при наследовании от Struct дам тебе args а также args= методы, это не даст вам @args переменная экземпляра.

Другие вопросы по тегам