※ 引述《nohaha (不是开玩笑的)》之铭言:
: 2.
: ruby有short-cicuiting的特性
: 当and前的值,为false,则无视and后的值为何,此式为false
: (e.g. if false and true => 结果为false)
: 当or前的值为true,则无视and后的值为何,此式为true
: (e.g. if true or false =>结果为true)
: 这部分我懂,但当拿fixnum来作运算时,我就不能理解结果了
short circuit 的特性在许多程式语言里面都有,它甚至还有一个 Wikipedia 条目:
http://en.wikipedia.org/wiki/Short-circuit_evaluation
简单来说就是,判定 if 条件的时候,若有多个条件,
则会依序执行条件,一但满足,就不再判断其他条件。
这种特性我猜是编译器编出来的机器语言所致,
不过我先不探讨编译出来的结果(其实是我不熟…)。
这种特性其实最明显会出现在“有副作用的 if condition”
什么叫有副作用呢?
通常的 if condition 是判断变量算出来的 boolean 值:
if @post.published? && @post.featured?
# ...
end
这种很常见的,单纯一问一答的 method ,人畜无害。
但如果今天这个 method 刚好有副作用,会修改到其他变量的内容,
例如 Rails 里面的 ActiveModel#valid?:
if @post.valid? && @comment.valid?
# response OK
else
# response @post.errors and @comment.errors
end
这时候如果 @post 跟 @comment 都不是 valid 的,就杯具了:
* 因为 short-circuit 特性,所以只有 @post.valid? 会被执行
* 然后 #valid? 其实会塞 errors 到该 instance 里面
* if 判断式因为第一个条件是 false 就跳到 else
* 于是,虽然 @comment 也不是 valid 但却没有被验证到
* 最后在 else 里面只能得到 @post.errors 而得不到 @comment.errors
以这个例子来说,要回避 short-circuit 的话,
就要确保全部都有 call 到 #valid? ,那么一个做法就是:
if [@post.valid?, @comment.valid?].all?
#...
做法是,先做一个 array ,里面填这两个 instance 的 #valid? 结果,
会是 true or false ,然后 call Array#all? 检查全部都是 true