如果Ruby变量未定义,则设置该变量

51
在Ruby中,如果变量未被定义,您如何将变量设置为特定值,并保留当前值(如果已经定义)?

你所说的“defined”是指“在当前范围内存在”,还是指“不等于 nil”? - zetetic
@zetetic:“它存在于当前作用域中” - jrdioko
4个回答

56

x ||= value 这样用时,它的意义是:如果 x 的值为 falsey,包括 nil(因为在赋值语句左边出现,所以它是隐含的),则将 value 赋值给 x。但这个操作只会做一次。

大致等同于以下代码。(但是,x ||= value 不会像这段代码 可能 抛出 NameError 异常,并且无论如何都会给 x 赋值,而这段代码不会。重点是要看出 x ||= value 对于 x 中的 任何 falsey 值,包括“默认”的 nil 值,都能产生相同的效果):

if !x
  x = value
end  

要查看变量是否真正未被赋值,请使用defined?方法:

>> defined? z
=> nil                                                                  
>> z = nil                                                              
=> nil                                                                  
>> defined? z                                                           
=> "local-variable"                                                     
>> defined? @z                                                          
=> nil                                                                  
>> @z = nil                                                             
=> nil                                                                  
>> defined? @z                                                          
=> "instance-variable" 

然而,在几乎所有情况下,使用defined?都是代码异味。小心使用权力。做明智的事情:在尝试使用变量之前给它们赋值 :)

愉快的编码。


2
@jrdioko "神奇" ;) 实际上,这与赋值语句左侧出现的 x 有关--即使尚未分配值(它将“默认”为 nil),也不会影响。例如,即使当前未定义 zz = z.nil? # => true 仍然成立。 - user166390
@pst 我觉得"defined?"方法只是比去检索“NameError: undefined local variable or method”更优雅的替代方案。所以真正的答案是当你的程序出错时,你会知道是否已经定义了一个变量。 - Dmitri
是的,如果您将变量设置为true/false,那么这样会更好。 - thenengah
@Dmitri @Codeglot 的确。最优雅的方式是编写代码,不能引起 NameError!(并通过良好的测试覆盖进行验证);-) - user166390
代码异味?更像是消除代码脆弱性,仅仅因为认为某种情况不可能发生并不意味着它永远不会发生。未来的开发可能会无意中使这个变量未定义(例如声明时拼写错误)。检查变量是否已定义将捕获此类错误,并使其易于找到。然而,如果没有进行检查,则问题可能不会那么快解决。 - SSH This
显示剩余4条评论

33
@variable ||= "set value if not set"

所以false变量将被覆盖

> @test = true 
 => true 
> @test ||= "test"
 => true 
> @test 
 => nil 
> @test ||= "test"
 => "test" 
> @test = false 
 => false 
> @test ||= "test"
 => "test" 

4
它可以设置为假值。因此,这只是大致正确的。 - user166390
你能澄清一下那是怎么工作的(以及假值如何处理)吗? - jrdioko
> @test should be > @test = nil - EliadL
今天我学到了:如果没有名为“owner”的键,像bodyParams['owner'] ||= ''这样的哈希值就无法工作。它会给你一个IndexError。关于这个问题,请查看这里https://dev59.com/GlkS5IYBdhLWcg3ws4gk#39549523 - Chris

8

由于您没有指定什么类型的变量:

v = v
v ||= 1

不建议使用局部变量来实现这个。

编辑:事实上,v=v并不需要。


1
它可以被设置为假值,然而。因此,这只是大致正确的。 - user166390
irb(main):007:0> v = v => nil // irb(main):008:0> v.class => NilClass // 所以与将其初始化为v = nil相同 - Dmitri
1
@Dmitri 不,它们不一样,如果v有一个值,它就不会改变。这就是重点。 - Victor Moroz

0

如果变量未定义(声明?),则它不存在,如果已声明,则知道如何初始化它,对吧?

通常,如果我只需要一个变量,但还不知道如何使用它 - 我知道永远不会将其用作布尔值 - 我会通过将其值设置为nil来初始化它。然后稍后可以轻松测试它是否已更改。

x = nil


some code


if x do 
[code that will only run if x has changed]
end

就这些。


它可以被设置为假值,但是这只是大致正确的。 - user166390
这是非常正确的,@pst 如果期望值是布尔类型,我不会使用这种技术。 - Dmitri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接