在Ruby中,|| =(or-equals)是什么意思?

时间:2009-06-15 11:25:13

标签: ruby operators

以下代码在Ruby中意味着什么?

||=

语法是否有任何意义或原因?

24 个答案:

答案 0 :(得分:530)

a ||= b条件赋值运算符。这意味着如果a未定义或falsey,则评估b并将a设置为结果。同样,如果a被定义并且评估为真实,那么b不会被评估,也不会发生任何分配。例如:

a ||= nil # => nil
a ||= 0 # => 0
a ||= 2 # => 0

foo = false # => false
foo ||= true # => true
foo ||= false # => true

令人困惑的是,它看起来与其他赋值运算符(例如+=)类似,但表现不同。

  • a += b转换为a = a + b
  • a ||= b大致翻译为a || a = b

这是a || a = b的近似简写。不同之处在于,当a未定义时,a || a = b会引发NameError,而a ||= b会将a设置为b。如果ab都是局部变量,那么这种区别就不重要了,但如果它们是类的getter / setter方法则很重要。

进一步阅读:

答案 1 :(得分:170)

在Ruby邮件列表和Ruby博客上经常讨论这个问题,现在Ruby邮件列表上甚至有线程,其唯一目的是收集所有其他线程的链接在讨论这个问题的Ruby邮件列表上。

这是一个:The definitive list of ||= (OR Equal) threads and pages

如果确实想知道发生了什么,请查看Ruby Language Draft Specification的第11.4.2.3节“缩写分配”。

作为第一个近似值,

a ||= b

相当于

a || a = b

等同于

a = a || b

然而,这只是第一次近似,特别是如果未定义a。语义也有所不同,这取决于它是简单的变量赋值,方法赋值还是索引赋值:

a    ||= b
a.c  ||= b
a[c] ||= b

都被区别对待。

答案 2 :(得分:32)

简明扼要的答案

a ||= b

的评估方式与以下相同

a || a = b
a ? a : a = b
if a then a else a = b end

-

另一方面,

a = a || b

的评估方式与以下相同

a = a ? a : b
if a then a = a else a = b end

-

编辑:正如AJedi32在评论中指出的那样,这只适用于:1。a是已定义的变量。 2.评估一次和两次不会导致程序或系统状态的差异。

答案 3 :(得分:23)

简而言之,a||=b表示:如果aundefined, nil or false,请将b分配给a。否则,请保持a完整。

答案 4 :(得分:12)

基本上,


x ||= y表示

如果x有任何值,请单独留下并且不要更改值,否则 将x设置为y

答案 5 :(得分:10)

这意味着或等于。它检查左侧的值是否已定义,然后使用它。如果不是,请使用右侧的值。您可以在Rails中使用它来缓存模型中的实例变量。

基于Rails的快速示例,我们创建一个函数来获取当前登录的用户:

class User > ActiveRecord::Base

  def current_user
    @current_user ||= User.find_by_id(session[:user_id])
  end

end

检查是否设置了@current_user实例变量。如果是,它将返回它,从而保存数据库调用。如果没有设置,我们进行调用,然后将@current_user变量设置为该调用。这是一种非常简单的缓存技术,但是当您在应用程序中多次获取相同的实例变量时,它非常适用。

答案 6 :(得分:8)

x ||= y

x || x = y

“如果x为假或未定义,则x指向y”

答案 7 :(得分:7)

准确地说,a ||= b表示"如果a未定义或假(falsenil),请将a设置为{{ 1}}并评估为(即返回)b,否则评估为b"。

其他人经常试图通过说a等同于a ||= ba || a = b来说明这一点。这些等价物有助于理解这个概念,但要注意它们在所有条件下都准确。请允许我解释一下:

  • a = a || ba ||= b

    a || a = b是未定义的局部变量时,这些语句的行为会有所不同。在这种情况下,a会将a ||= b设置为a(并评估为b),而b会提升a || a = b

  • NameError: undefined local variable or method 'a' for main:Objecta ||= b

    通常假设这些陈述的等效性,因为其他abbreviated assignment运算符(即a = a || b+=-=,{{1} },*=/=%=**=&=|=^=)。但是,对于<<=,当>>=是对象上的方法且||=是真实的时,这些语句可能的行为会有所不同。在这种情况下,a=将不执行任何操作(评估为a除外),而a ||= b将在a的接收方上调用a = a || b。正如others指出的那样,当调用a=(a)有副作用时,例如向哈希添加键时,这会有所不同。

  • aa=a ??

    这些陈述的行为仅在a ||= b真实时评估的内容上有所不同。在这种情况下,a = b unless a将评估为a(尽管a = b unless a仍未按预期设置),而nil将评估为a。< / p>

  • a ||= ba ????

    仍然没有。当存在a ||= b方法并返回defined?(a) ? (a || a = b) : (a = b)的真值时,这些语句可能会有所不同。在这种情况下,method_missing将评估为a次返回,并且不会尝试设置a ||= b,而method_missing会将a设置为defined?(a) ? (a || a = b) : (a = b)并评估为a

好的,好吧, b等同于什么?有没有办法在Ruby中表达这个?

好吧,假设我没有忽视任何事情,我相信b在功能上等同于...( drumroll

a ||= b

等一下!难道这不是第一个带有noop的例子吗?嗯,不太好。还记得我之前说过a ||= bbegin a = nil if false a || a = b end 是未定义的局部变量时只与a ||= b不等同吗?好吧,a || a = b确保永远不会定义a,即使该行永远不会被执行。 Ruby中的局部变量是词法范围的。

答案 8 :(得分:3)

如果X没有值,则将为其分配值Y。否则,它将保留其原始值,在本示例中为5:

irb(main):020:0> x = 5
=> 5
irb(main):021:0> y = 10
=> 10
irb(main):022:0> x ||= y
=> 5

# Now set x to nil. 

irb(main):025:0> x = nil
=> nil
irb(main):026:0> x ||= y
=> 10

答案 9 :(得分:3)

unless x x = y end

除非x具有值(它不是nil或false),否则将其设置为y

相当于

x ||= y

答案 10 :(得分:3)

假设a = 2b = 3

然后,a ||= b会产生a的值,即2

当评估某个值未导致falsenil时...这就是为什么ll不评估b的值。

现在假设a = nilb = 3

然后a ||= b会产生3,即b的值。

首先尝试评估导致nil的值...所以评估b的值。

ror app中使用的最佳示例是:

#To get currently logged in iser
def current_user
  @current_user ||= User.find_by_id(session[:user_id])
end

# Make current_user available in templates as a helper
helper_method :current_user

当且仅当User.find_by_id(session[:user_id])之前未初始化时才会触发@current_user

答案 11 :(得分:2)

这是默认的赋值表示法

例如:x || = 1
这将检查x是否为零。如果x确实为零,则它将为其分配新值(在我们的示例中为1)

更明确:
如果x == nil
x = 1

答案 12 :(得分:2)

还请记住docker run -it --entrypoint bash dockerfile/rabbitmq:latest [ root@0c5920d3559e:/data ]$ rabbitmq-start 不是原子操作,因此它不是线程安全的。根据经验,不要将它用于类方法。

答案 13 :(得分:2)

这就像懒惰的实例化。 如果已经定义了变量,它将采用该值而不是再次创建该值。

答案 14 :(得分:2)

a ||= b

相当于

a || a = b

而不是

a = a || b

因为您使用默认值定义哈希的情况(哈希将返回任何未定义键的默认值)

a = Hash.new(true) #Which is: {}

如果您使用:

a[10] ||= 10 #same as a[10] || a[10] = 10

a仍然是:

{}

但是当你这样写时:

a[10] = a[10] || 10

a成为:

{10 => true}

因为你已经在键10分配了自己的值,默认为true,所以现在为键10定义了哈希,而不是从不首先执行赋值

答案 15 :(得分:1)

作为一种常见的误解,a ||= b不等同于a = a || b,但其行为与a || a = b相同。

但这是一个棘手的案例。如果未定义a,则a || a = 42会引发NameError,而a ||= 42会返回42。所以,它们似乎不是等同的表达方式。

答案 16 :(得分:1)

此ruby-lang语法。正确的答案是检查ruby-lang文档。 所有其他说明都难以理解

Google

“ ruby​​-lang docs缩写分配”。

Ruby-lang文档

https://docs.ruby-lang.org/en/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment

答案 17 :(得分:0)

irb(main):001:0> a = 1
=> 1
irb(main):002:0> a ||= 2
=> 1

因为a已设置为1

irb(main):003:0> a = nil
=> nil
irb(main):004:0> a ||= 2
=> 2

因为anil

答案 18 :(得分:0)

b = 5
a ||= b

这转换为:

a = a || b

将是

a = nil || 5

所以最后

a = 5

现在,如果你再次打电话:

a ||= b
a = a || b
a = 5 || 5
a = 5

b = 6

现在,如果你再次打电话:

a ||= b
a = a || b
a = 5 || 6
a = 5 

如果您发现,b值将不会分配给aa仍有5

它是一个Memoization模式,在Ruby中用于加速访问器。

def users
  @users ||= User.all
end

这基本上转化为:

@users = @users || User.all

因此,您第一次调用此方法时将调用数据库。

将来对此方法的调用只会返回@users实例变量的值。

答案 19 :(得分:0)

|| = 条件赋值运算符

  x ||= y

等同于

  x = x || y

if defined?(x) and x
    x = x
else 
    x = y
end

答案 20 :(得分:0)

a || = b

表示'a'中是否存在任何值,并且您不想使用该值更改保持值,否则,如果'a'没有任何值,则使用'b'值。

简单的单词,如果左侧不为null,则指向现有值,否则指向右侧的值。

答案 21 :(得分:0)

||=仅在left == nil(或未定义或false)时才向右分配值。

答案 22 :(得分:-1)

INSERT INTO `Patients` (`patientId`, `name`, `address`, `etage`, `Door`, `Elevator`, `key_number`, `medicineId`, `doctorId`) VALUES (109, 'Muller', 'bla bla bla ', 3, 'links', 1 , 'S12' ,'m9' , 'D11'); INSERT INTO `PatientsDetail` (`patientId`, `lid`) VALUES (109, 02.0), (109, 2.10), (109, 2.30); 被称为条件赋值运算符。

它基本上可以作为||=使用,但有一个例外,即如果已经指定了变量 则它将不执行任何操作。

第一个例子:

=

第二个例子:

x ||= 10

在第一个示例中,x = 20 x ||= 10 现在等于10.但是,在第二个示例中,x已经定义为20.因此条件运算符无效。运行x后,x仍然是20。

答案 23 :(得分:-1)

'gitlab-runner' is not recognized as an internal or external command, operable program or batch file.与说a ||= ba = b if a.nil?

相同

但是,所有3个选项都显示相同的性能吗?使用Ruby 2.5.1,

a = b unless a

在我的PC上花费0.099秒,而

1000000.times do
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
end

花费0.062秒。快了将近40%。

然后我们还有:

1000000.times do
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
end

需要0.166秒。

并不是说这通常会对性能产生重大影响,但是如果您确实需要最后的优化,请考虑此结果。 顺便说一句:1000000.times do a = 1 if a.nil? a = 1 if a.nil? a = 1 if a.nil? a = 1 if a.nil? a = 1 if a.nil? a = 1 if a.nil? a = 1 if a.nil? a = 1 if a.nil? a = 1 if a.nil? a = 1 if a.nil? end 对于新手来说更容易阅读,它是不言自明的。

注1:多次重复分配行的原因是为了减少所测量时间的循环开销。

注2:如果我在每次作业前都没做a = 1 unless a无,结果将是相似的。