【问题标题】:some trouble with yield in ruby红宝石产量的一些问题
【发布时间】:2014-05-08 14:37:02
【问题描述】:

我运行一个简单的函数:

def test 
   a = 10
   yield a
   puts a
end

test { |x| x += 10 }

得到意想不到的答案

> 10

接下来,我尝试以这种方式重用该函数:

def test 
   a = 10
   a = yield a
   puts a
end

结果是

 > 20

但我觉得这段代码很丑,而且不是 ruby​​ 风格的,我该如何改进它?

【问题讨论】:

  • test { |x| x += 10 } 传递给def test; a = 10; yield a; puts a; end 计算结果为def test; a = 10; 20; puts a; end。您可以看到 a 并没有因此而改变。是的,Ruby 有时看起来有点朴素,但还是很漂亮。您的第二次尝试非常符合“Ruby 风格”。
  • 我唯一要改变的是块本身:{ |x| x + 10 }

标签: ruby yield


【解决方案1】:

理论:

在 ruby​​ 中,一切都是参考。这是什么意思?您使用的每一位数据(如数字 10 或字符串 'hello world')都是在内存中的某个位置创建的。而所有的变量(也放在内存中)只是指向这些对象占用的内存位置。

有两种类型的对象——可变的和不可变的。可变对象可以被修改,即如果我们在内存中放置了一个字符串“hello”,我们可以修改它而不改变它在内存中的位置,所以指向它位置的所有其他变量也会产生改变的值。示例:

a = b = 'hello'
a[2] = 'b'

a   #=> 'heblo'
b   #=> 'heblo'

因此,您已经在内存中创建了“hello”字符串对象,并将变量 a 和 b 指向其内存位置。现在如果你修改它,因为两个变量都指向同一个位置,这两个变量似乎都被改变了。然而新值的赋值

a = 'foo'
b #=> 'heblo'

没有修改对象。而是在内存中创建一个新对象并将变量 b 指向该对象的内存位置。另请注意:

a = 'foo'
b = 'foo'

会在内存中创建两个独立的对象,变量a和b指向不同的位置。

不可变对象不能被修改,也不能被复制。这意味着在内存中总是最多有一个位置代表给定对象。例如,所有的 Fixnum 都是不可变的(还有 nil、false、true 和符号)。因此这段代码:

a = 1
b = 1

将使两个变量指向内存中的同一位置。这并不重要,因为存储在那里的对象无论如何都无法修改。

你的问题:

那么当您将变量生成到块中时会发生什么。创建新变量以指向内存中的相同位置。由于您要生成一个固定编号,它是不可变的,因此无法修改。所以 `x += 10' 实际上将新的局部变量 x 重新指向内存中的不同位置,因此原始 x 没有改变。

如果你传递一个字符串并对其进行修改,它看起来会有所不同:

def test
  a = 'foo'
  yield a
  puts a
end

test { a.replace 'bar' }

# Output: 'bar'

注意replace 方法,它修改字符串而不重新指向内存指针。

【讨论】:

    【解决方案2】:

    假设你有这个功能:

    def test(x)
      x += 10
    end
    

    如果我有:

    a = 10
    test(a)
    

    a 不会改变。所以在你的例子中,a 在块执行后仍然是 10。

    如果有的话,你可以这样做:

    def test 
       puts yield 10
    end
    

    【讨论】:

      【解决方案3】:

      与几乎所有现代语言一样,Ruby 是按值传递的。您不能在调用者的范围内改变变量绑定。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-18
        • 2016-03-23
        • 2011-01-09
        • 2016-05-16
        • 1970-01-01
        • 2015-07-17
        • 1970-01-01
        • 2011-05-24
        相关资源
        最近更新 更多