我正在研究Ruby,并输入了一段代码来尝试块范围变量:
x = 10
3.times do |i; x|
x = x + 1
puts("inside block is #{x}")
end
puts("outside block is #{x}")
我希望x块变量能够自动捕获x全局变量的值,然后每次在块内将x设置为11,将x置于要保护的块外,并保持为10。 “动作是网络上许多Ruby教程中所描述的。
但是,脚本失败了,告诉我x为nil,并且没有+
函数。换句话说,x块变量尚未使用值初始化。
上面的精确代码位于名为delete_me.rb
的文件中,并运行:
ruby delete_me.rb
运行脚本时,出现以下错误:
delete_me.rb:3:in `block in <main>': undefined method `+' for nil:NilClass (NoMethodError)
from delete_me.rb:2:in `times'
from delete_me.rb:2:in `<main>'
如何在Ruby中初始化块变量的值?
答案 0 :(得分:2)
我希望x块变量能够自动捕获x全局变量的值
这不是Ruby的工作方式,也没有理由期望它具有这种行为。用我所知道的任何语言,内部变量永远都不会从被遮盖的变量获取其值。那将是一种可怕的设计语言,可以更改或引入无关的外部上下文,从而以完全无法预料的方式破坏内部范围。 范围的全部目的是预防这种事情。
x
是nil
,因为它是新引入的变量,您没有为其分配值。
如何在Ruby中初始化块变量的值?
您可以检查它是否为nil
,然后为其分配一个值:
x = 10
3.times do |i; x|
x ||= 0
x = x + 1
puts("inside block is #{x}")
end
puts("outside block is #{x}")
请注意,此循环将打印"inside block is 1"
,三次。您要创建一个新的x
,并在每次调用该块时将其设置为0。如果要在迭代时累积状态,这是错误的处理方式。您要么不遮盖外部x
,要么使用其他inject
或each.with_object
之类的Enumerable方法。
答案 1 :(得分:0)
这是因为在ruby块中没有创建新的作用域,而是在查找表中创建了变量。
您的块可以访问全局x,但您要将x作为参数传递给块。当时间迭代时,它将传递i,并且x设置为nil,因为它没有传递变量。因此,在您的块中,您有一个新的x,每次迭代的值为nil。如果您传入任何其他命名变量,它将起作用。
x = 10
3.times do |i; y|
x = x + 1
puts("x block is #{x}")
end
puts("outside block is #{x}")
更好的是,除非要覆盖任何全局变量,否则不要用其他参数定义它
x = 10
3.times do |i|
x = x + 1
puts("x block is #{x}")
end
puts("outside block is #{x}")