Ruby:如何初始化块变量的值

时间:2018-09-19 16:47:05

标签: ruby

我正在研究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中初始化块变量的值?

2 个答案:

答案 0 :(得分:2)

  

我希望x块变量能够自动捕获x全局变量的值

这不是Ruby的工作方式,也没有理由期望它具有这种行为。用我所知道的任何语言,内部变量永远都不会从被遮盖的变量获取其值。那将是一种可怕的设计语言,可以更改或引入无关的外部上下文,从而以完全无法预料的方式破坏内部范围。 范围的全部目的是预防这种事情。

xnil,因为它是新引入的变量,您没有为其分配值。

  

如何在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,要么使用其他injecteach.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}")