a
Здесь вы оцениваете a
, что не определено. Поэтому вы получаете исключение.
a || 1
Здесь вы еще должны оценить a
определить значение логического выражения. Как и выше, a
не определен. Поэтому вы получаете исключение.
a = a || 1
Здесь a
является определена. Он определяется как неинициализированная локальная переменная. В Ruby, неинициализированные переменные вычисляются в nil
, так что правая часть выражения присваивания вычисляется в nil || 1
, который принимает значение 1
, так что возвращаемое значение выражения присваивания является 1
и побочный эффект заключается в том, что a
инициализируется 1
.
EDIT: Кажется, что есть некоторая путаница, когда переменные определяются и когда они инициализируются в 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
, потому что это неинициализированное.
Дубликат http://stackoverflow.com/questions/1462407/ruby-edge-cases –