Ruby 2.2.4, лексирующий назначение в условном выражении

В чем разница между этими двумя строками кода?

a = (b if (b = "test"))
a =  b if (b = "test")

Первый работает нормально и устанавливает оба a а также b в test, но второй выдает ошибку:

NameError: неопределенная локальная переменная или метод `b'для main:Object

Я бы предположил, что для второй строки, Ruby будет оценивать b = "test" будет первый if "test", и наконец a = b, Что на самом деле происходит?

(Ruby версия 2.2.4)

1 ответ

Решение

Обе строки не будут работать. И обе линии будут работать. Это выражение Шредингера:).

Вы можете запустить его дважды в новом репле:

a =  b if b = "test"
#=> NameError: undefined local variable or method `b' for main:Object
a =  b if b = "test"
#=> "test"

Давайте посмотрим глубже, откроем новый репл:

defined(b)
#=> nil
a = b if b = "test"
#=> NameError: undefined local variable or method `b' for main:Object
defined(b)
#=> local-variable
b
#=> "test"
a = b if b = "test"
#=> "test"

Так что на самом деле Руби оценил b = "test" часть и определил эту переменную в текущей области видимости. Оба выражения a = b а также if b = "test" были выполнены. Более того, если оператор выполняется перед оператором присваивания:

c = p("assignment") && b if b = p("if") && "test"
#=> "if"
#=> "assignment"
#=> NameError: undefined local variable or method `b' for main:Object

Но b переменная не была определена в области действия оператора присваивания, когда она была оценена впервые. А на втором подходе это уже было определено, так что вы получили правильный результат.

Итак, никогда не делайте заданий таким образом

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