【问题标题】:Why Symbol#to_proc has such type of behaviour?为什么 Symbol#to_proc 有这种行为?
【发布时间】:2014-01-31 01:54:42
【问题描述】:

我发现这个在 Ruby 中实现自定义 Symbol#to_proc 的示例代码:

class Symbol
  def to_proc
    puts "In the new Symbol#to_proc!"
    Proc.new { |obj| obj.send(self) }
  end
end

它包括额外的“puts ...”字符串以确保它不是内置方法。当我执行代码时

p %w{ david black }.map(&:capitalize)

结果是:

In the new Symbol#to_proc!
["David", "Black"]

但为什么不是这样呢?

In the new Symbol#to_proc!
["David"]
In the new Symbol#to_proc!
["Black"]

我的逻辑是这样的:map 产生元素一个一个地阻塞。 Block 接受第一个元素并执行 .to_proc,而不是第二个。但是为什么 puts 只执行一次呢?

【问题讨论】:

标签: ruby


【解决方案1】:

to_proc 方法被调用一次以返回一个 Proc 对象,该对象随后被重复使用,因此您看到了正确的行为。

如果你把 put 移到里面,你会看到你所期待的:

class Symbol
  def to_proc
    Proc.new { |obj|
      puts "In the new Symbol#to_proc!"
      obj.send(self)
    }
  end
end

【讨论】:

  • 感谢您的解释,但我不明白为什么 Proc 对象只创建一次。为什么不为每个地图块调用创建新的 Proc 对象?我确信 Ruby 可以正确执行代码,但我无法为这种情况找到一个好的解释。
  • 为什么要为每个循环创建一个全新的 proc?这将是非常浪费的,因为map 和类似函数的整个想法是将完全相同的函数应用于多个对象。如果你想对每个元素应用不同的函数,你应该使用 each 并在其中添加一段自定义代码。这为您提供了最大的灵活性。
【解决方案2】:

在 Ruby 中,map 与块一起工作。 & 运算符在其后的对象上调用to_proc,并将调用to_proc 返回的值作为block 传递给映射。有了这些信息,让我们再看看你的例子。在您的示例中,&:capitalize 将导致对:capitalize 上的to_proc 方法的调用。因为:capitalize 是一个符号,它会在符号类上调用to_proc,由你重新定义。

:capitalize.to_proc

将返回:

In the new Symbol#to_proc!
=> #<Proc:0x007fa08183df28@(irb):4>

&amp; 运算符将使用返回的 Proc 对象,并将该 proc 对象作为块传递给映射。在您重新定义的to_proc 方法定义中,puts 刚刚被执行,并且由于puts 打印到控制台(假设您在控制台中运行它),您将看到它打印出来。它从未传递给地图,因此您永远不会看到它被打印两次。

但是,如果您希望获得预期的行为,请使用第一个答案。希望对您有所帮助。

【讨论】:

  • 这是一个完美的答案,现在我明白发生了什么。谢谢!
猜你喜欢
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多