【问题标题】:RoR: Meaning of "user ||= User.new" [duplicate]RoR:“用户||= User.new”的含义[重复]
【发布时间】:2012-08-11 02:56:59
【问题描述】:

可能重复:
What does ||= (or equals) mean in Ruby?

Out on the internet 我在 Ruby/Rails 中看到过以下语法:

user ||= User.new

我是新手,我无法解析这个。有人可以向我解释一下“||=" 运算符的作用吗?

【问题讨论】:

  • 啊,对不起。我尝试在 SO 上将 '||=' 放入搜索框中,但没有出现任何结果。也许我的查询被解释为几个布尔运算符而不是字符串?我搜索的方式不对吗?
  • 我不确定 SO 如何处理 ||= 之类的字符。我使用英文单词或等号搜索。
  • 我下次试试。谢谢。

标签: ruby-on-rails ruby


【解决方案1】:

语句将user 设置为自身(如果它已经是现有对象)或User.new(如果user 为null,它将创建一个新用户)。这是一个逻辑或,可以避免分配空用户对象。

代码是简写

user = user || User.new

如果用户为空,那么用户将被设置为User.new

【讨论】:

    【解决方案2】:

    如果user 已经设置,则什么都不做,否则它将分配一个新的User 对象(使用User.new 创建)。

    According to David A. Black,《The Well-Grounded Rubyist》的作者:

    x ||= y 表示:x || x = y

    不同之处在于,如果 x 未定义,x ||= y 不会报错, 而如果你输入 x || x = y 并且范围内没有 x,它会。

    对于一些补充细节,这里是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 定义在node.h:

    #define NEW_OP_ASGN_OR(i,val) NEW_NODE(NODE_OP_ASGN_OR,i,val,0)
    

    NEW_NODE 看起来像这样:

    #define NEW_NODE(t,a0,a1,a2) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))
    

    寻找NODE_OP_ASGN_OR 导致compile.c,其中有趣的部分如下所示:

    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;
     }
    

    我认为这比我想知道的关于 Ruby 分配的更多信息,但查找它相当有趣。

    【讨论】:

    • x ||= y 表示:x = x ||是的
    【解决方案3】:

    它基本上是一个快捷方式:

    user = user || User.new
    

    或为了更好地理解:

    if user.nil?
        user = User.new
    end
    

    我敢打赌,你以前见过类似的符号,比如“+”这样的运算符

    i += 1
    

    也可以写成:

    i = i + 1
    

    【讨论】:

    • 不仅nil,还有false
    【解决方案4】:

    这个语句等价于

    user = user || User.new
    

    相当于

    user = user ? user : User.new
    

    当且仅当 usernil 时,它会将 User.new 的值分配给变量 user。如果不是,user 的内容将保持不变。

    【讨论】:

    • 这里相同,nilfalse,不仅仅是nil
    • 我可能是错的,但如果他们不熟悉||=,我不希望他们熟悉?:
    • 为什么?许多语言都有三元运算符,但并非所有语言都有||=
    • @MichaelKohl 当然你是对的。
    【解决方案5】:

    相当于user = user || User.new

    这依赖于|| 运算符的短路行为。如果表达式的左侧为真,那么无论右侧是什么,整个表达式都为真,因此运算符“短路”并停止计算。 || 运算符不是返回布尔值“true”,而是返回它评估的最后一个值。

    因此,||= 对于分配默认值很有用。如果user 有值,则user || User.new 计算为user,否则计算为User.new,这是默认值。

    等效的块是:

    if user
        user = user
    else 
        user = User.new
    end 
    

    【讨论】:

      猜你喜欢
      • 2019-12-17
      • 1970-01-01
      • 2014-04-15
      • 2019-07-12
      • 1970-01-01
      • 1970-01-01
      • 2015-03-07
      • 2016-10-22
      • 2018-01-05
      相关资源
      最近更新 更多