Почему в Ruby, || 1 выдаст ошибку, когда `a` не определено, но a = a || 1 не будет? - PullRequest
7 голосов
/ 06 июня 2010

Если a не определено, то a || 1 выдаст ошибку, а a = a || 1 - нет. Разве это не немного противоречиво?

irb(main):001:0> a
NameError: undefined local variable or method 'a' for main:Object
        from (irb):1
        from c:/ruby/bin/irb:12:in '<main>'

irb(main):002:0> a || 1
NameError: undefined local variable or method 'a' for main:Object
        from (irb):2
        from c:/ruby/bin/irb:12:in '<main>'

irb(main):003:0> a = a || 1
=> 1

Ответы [ 3 ]

9 голосов
/ 06 июня 2010
a

Здесь вы оцениваете a, который не определен. Следовательно, вы получаете исключение.

a || 1

Здесь вы все еще должны оценить a, чтобы определить значение логического выражения. Как и выше, a не определено. Следовательно, вы получаете исключение.

a = a || 1

Здесь a определяется . Он определен как неинициализированная локальная переменная. В Ruby неинициализированные переменные оцениваются как nil, поэтому правая часть выражения присваивания оценивается как nil || 1, что соответствует 1, поэтому возвращаемое значение выражения присваивания равно 1, и побочный эффект состоит в том, что a инициализируется как 1.

РЕДАКТИРОВАТЬ: Кажется, что есть некоторая путаница, когда переменные определяются и когда они инициализируются в Ruby. Получение определяется в время разбора , но инициализируется в время выполнения . Вы можете увидеть это здесь:

 foo # => NameError: undefined local variable or method `foo' for main:Object

foo не определено.

if false
  foo = 'This will never get executed'
end

На этом этапе определяется foo, даже если строка никогда не будет выполнена. Тот факт, что строка никогда не выполняется, совершенно не имеет значения, потому что интерпретатор в любом случае не имеет к этому никакого отношения: локальные переменные определяются синтаксическим анализатором, и синтаксический анализатор, очевидно, видит эту строку.

foo # => nil

Нет ошибки, потому что определено foo, и оно оценивается как nil, потому что оно не инициализировано.

1 голос
/ 06 июня 2010

Когда вы делаете a || 1, вы просите его найти значение a, которое не определено.

Когда вы делаете a = a || 1, вы просите его найти значение присвоения a a, которое, по-видимому, не дает ошибки.

Так что, хотя и странно, я не считаю это противоречивым.

0 голосов
/ 06 июня 2010

Это то, что вы имеете в виду?

if !(defined? a) then
    a = 1
end

Может быть проще объявить значение со значением 1 по умолчанию.

...