可能重复:
||=(或等于)在 Ruby 中是什么意思?
在互联网上,我在 Ruby/Rails 中看到了以下语法:
user ||= User.new
我是新手,我无法解析这个。有人可以向我解释“||=”运算符的作用吗?
可能重复:
||=(或等于)在 Ruby 中是什么意思?
在互联网上,我在 Ruby/Rails 中看到了以下语法:
user ||= User.new
我是新手,我无法解析这个。有人可以向我解释“||=”运算符的作用吗?
If user
is already set this does nothing, otherwise it will assign a new User
object (created with User.new
).
According to David A. Black, author of "The Well-Grounded Rubyist":
x ||= y means: x || x = y
The difference is that x ||= y won't complain if x is undefined, whereas if you type x || x = y and there's no x in scope, it will.
For some added details, here's the relevant part of parse.y:
| var_lhs tOP_ASGN command_call
{
/*%%%*/
value_expr($3);
if ($1) {
ID vid = $1->nd_vid;
if ($2 == tOROP) {
$1->nd_value = $3;
$$ = NEW_OP_ASGN_OR(gettable(vid), $1);
if (is_asgn_or_id(vid)) {
$$->nd_aid = vid;
}
}
else if ($2 == tANDOP) {
$1->nd_value = $3;
$$ = NEW_OP_ASGN_AND(gettable(vid), $1);
}
else {
$$ = $1;
$$->nd_value = NEW_CALL(gettable(vid), $2, NEW_LIST($3));
}
}
NEW_OP_ASGN_OR
is defined in node.h
:
#define NEW_OP_ASGN_OR(i,val) NEW_NODE(NODE_OP_ASGN_OR,i,val,0)
NEW_NODE
looks like this:
#define NEW_NODE(t,a0,a1,a2) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))
Looking for NODE_OP_ASGN_OR
leads to compile.c
, where the interesting part looks like this:
case NODE_OP_ASGN_OR:{
LABEL *lfin = NEW_LABEL(nd_line(node));
LABEL *lassign;
if (nd_type(node) == NODE_OP_ASGN_OR) {
LABEL *lfinish[2];
lfinish[0] = lfin;
lfinish[1] = 0;
defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
lassign = lfinish[1];
if (!lassign) {
lassign = NEW_LABEL(nd_line(node));
}
ADD_INSNL(ret, nd_line(node), branchunless, lassign);
}
else {
lassign = NEW_LABEL(nd_line(node));
}
COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head);
ADD_INSN(ret, nd_line(node), dup);
if (nd_type(node) == NODE_OP_ASGN_AND) {
ADD_INSNL(ret, nd_line(node), branchunless, lfin);
}
else {
ADD_INSNL(ret, nd_line(node), branchif, lfin);
}
ADD_INSN(ret, nd_line(node), pop);
ADD_LABEL(ret, lassign);
COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value);
ADD_LABEL(ret, lfin);
if (poped) {
/* we can apply more optimize */
ADD_INSN(ret, nd_line(node), pop);
}
break;
}
I think this is more than I ever wanted to know about assignment in Ruby, but it was rather entertaining to look this up.
It's basically a shortcut for:
user = user || User.new
or for better understanding:
if user.nil?
user = User.new
end
I bet you've seen similar notations before with operators like '+'
i += 1
which can also be written out as:
i = i + 1
该语句等价于
user = user || User.new
这相当于
user = user ? user : User.new
当且仅当为nil时,它会将 的值分配给User.new
变量。如果不是,则 的内容将保持不变。user
user
user
它相当于user = user || User.new
.
这取决于操作员的短路行为||
。如果表达式的左侧为真,那么无论右侧是什么,整个表达式都为真,因此运算符“短路”并停止计算。而不是返回一个布尔值“真”,该||
运算符返回它评估的最后一个值。
因此,||=
对于分配默认值很有用。如果user
有一个值,则user || User.new
评估为,user
否则评估为User.new
哪个是默认值。
一个等效的块是:
if user
user = user
else
user = User.new
end
The statement set user
to itself (if it is already an existing object) or User.new
(which will create a new user if user is null). It's a logical OR that will avoid having an assigned null user object.
The code is a shorthand for
user = user || User.new
If user is null, then user will be set to User.new
.