微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ruby – 允许在Enumerable中阻止链接吗?

在很多情况下,通过互联网我看到Enumerable的每个方法的例子如下:

def each(&block)
  @items.each do |item|
    block.call(item)
  end
end

为什么人们不使用这个:

def each(&block)
  @items.each(&block)
end

有什么不同吗?

解决方法

实际上我认为以下版本更常见:

def each
  @items.each { |i| yield i }
end

这相当于您的第一个代码示例.然而,这与您的第二个版本之间存在细微差别:

class Test
  def initialize(items)
    @items = items
  end

  def each1
    @items.each { |i| yield i }
  end

  def each2(&block)
    @items.each(&block)
  end
end

注意:

irb(main):053:0> Test.new([1,2,3]).each2
=> #<Enumerator: [1,3]:each>
irb(main):054:0> Test.new([1,3]).each1
LocalJumpError: no block given (yield)
    from (irb):43:in `block in each1'
    from (irb):43:in `each'
    from (irb):43:in `each1'
    from (irb):54
    from /usr/bin/irb:12:in `<main>'

如果没有给出块,那么将块委托给底层iterable的版本实际上会返回一个枚举器,这非常好.它允许我们写这样的东西:

irb(main):055:0> Test.new([1,3]).each2.map { |x| x + 1 }
=> [2,3,4]

为了实现与我们的显式版本相同,我们必须像这样调整它:

def each1
  return enum_for(:each1) unless block_given?
  @items.each { |i| yield i }
end

哪个更加冗长.底线:尽可能将块委托给底层枚举,以避免代码重复和这些微妙的陷阱.

顺便说一下,既然你已经意识到每种方法的双重性质,那么将它命名为不同的方法是有意义的.例如,您可以按照String#chars或IO#行等方法的示例来调用方法项:

def items(&block)
  @items.each(&block)
end

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐