红宝石产量有些麻烦

时间:2014-03-28 22:59:38

标签: ruby yield

我运行一个简单的函数:

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

但是我发现这段代码很难看,而且不是红宝石式的,我怎么能改进呢?

3 个答案:

答案 0 :(得分:3)

理论:

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

有两种类型的对象 - 可变和不可变。可以修改可变对象,即如果我们有一个字符串'你好'放在内存中,我们可以修改它而不改变它在内存中的位置,因此指向其位置的所有其他变量也将产生更改的值。例如:

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

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

所以你创造了'你好''内存中的字符串对象,并将变量a和b指向其内存位置。现在,如果你修改它,因为两个变量都指向同一个位置,所以两个变量似乎都被改变了。然而,新价值的确定

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

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

a = 'foo'
b = 'foo'

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

不可变对象无法修改且无法复制。这意味着存储器中最多总有一个位置代表给定对象。例如,所有Fixnums都是不可变的(也是nil,false,true和symbols)。因此这段代码:

a = 1
b = 1

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

您的问题:

那么当你将一个变量输入一个块时会发生什么。创建新变量以指向内存中的相同位置。由于您正在产生一个fixnum,whcih是不可变的,因此无法修改。所以'x + = 10'实际上将新的局部变量x重新分配到内存中的不同位置,因此原始x不会改变。

如果你传递一个字符串并修改它会有所不同:

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

test { a.replace 'bar' }

# Output: 'bar'

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

答案 1 :(得分:2)

说你有这个功能:

def test(x)
  x += 10
end

如果我有:

a = 10
test(a)

a不会改变。因此,在您的示例中,a在块执行后仍为10。

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

def test 
   puts yield 10
end

答案 2 :(得分:1)

像许多现代语言一样,Ruby是值得传递的。你不能改变来自调用者范围的变量绑定。