【发布时间】:2011-05-28 20:58:40
【问题描述】:
如果这是一个新问题,请原谅我,但我正在阅读一本关于 Rails 的书,其中作者在辅助方法中使用了这个表达式:
@current_user ||= User.find_by_id(session[:user_id])
这种双管道的使用仍然是布尔 OR 语句吗?
如果是这样,它是如何工作的?
【问题讨论】:
标签: ruby boolean variable-assignment
如果这是一个新问题,请原谅我,但我正在阅读一本关于 Rails 的书,其中作者在辅助方法中使用了这个表达式:
@current_user ||= User.find_by_id(session[:user_id])
这种双管道的使用仍然是布尔 OR 语句吗?
如果是这样,它是如何工作的?
【问题讨论】:
标签: ruby boolean variable-assignment
这是一个条件赋值。来自here:
x = find_something() #=>nil
x ||= "default" #=>"default" : value of x will be replaced with "default", but only if x is nil or false
x ||= "other" #=>"default" : value of x is not replaced if it already is other than nil or false
【讨论】:
你可以把它看作是:
@current_user = @current_user || User.find_by_id(session[:user_id])
@current_user 首先被评估,如果它不为空,则 OR 短路,返回 @current_user 的值,而不是调用 User.find_by_id。
(这仅是因为 Ruby 在布尔上下文中将 null 视为 false,将 non-null 视为 true。它不适用于像 Java 这样不将非布尔值视为真实的语言。)
【讨论】:
true!如果非nil 和非false,它评估 为@current_user 的值。
代码foo ||= bar 几乎等同于foo = foo || bar。在 Ruby(在许多语言中,如 JavaScript 或 Io)中,布尔运算符是“守卫”运算符。它们不会总是返回 true 或 false,而是计算第一个计算结果为“真实”值的操作数的值。
例如,此代码 foo = 1 || delete_all_files_from_my_computer() 不会删除任何内容:foo 将被设置为 1 并且第二个操作数甚至不会被计算。
在 Ruby 中,唯一的“非真实”值是 nil 和 false。因此,如果foo 是nil 或false,则代码foo ||= bar 只会评估bar 并将foo 设置为结果。
由于实例变量在未设置时默认为nil,因此@foo ||= bar 之类的代码是一个常见的Ruby 习惯用法,用于设置尚未设置的实例变量。
【讨论】:
foo ||= bar有点相当于foo || foo = bar和不foo = foo || bar(已经在 StackOverflow 上讨论过十几次,在 Ruby 邮件列表中讨论过大约一百万次),但只是有点。 ||= 的精确扩展还没有找到,我个人怀疑||= 的语义是否可以用Ruby表达。到目前为止,我看到的关于 ||= 工作原理的最清晰描述是 ISO Draft Ruby 语言规范中给出的评估算法,除了我几乎确信该算法是错误。
||=的新手来说,匹配其他?=复合赋值运算符的简单心智模型就足够了。尽管如此,我还是从我的回答中删除了“完全是”这个词。