超类的产量绕过Ruby中的子类块

时间:2015-04-27 07:56:56

标签: ruby

假设我有两个类:

  • 超类Inner有一个方法func,可以为调用者提供值。
  • 子类Outer有一个重写方法func,它调用Inner.func,对产生的值执行某些操作,然后将它们依次发送给自己的调用方。

当我运行此示例代码时,Outer中的块被跳过,我得到了这个奇怪的undefined method错误:

# subclassed.rb

class Inner
  def func
    puts '  Inner entered func'
    yield 1
    yield 2
    yield 3
    puts '  Inner leaving func'
  end
end

class Outer < Inner
  def func
    puts 'Outer entered func'
    super.func do |value|
      puts "    Outer received #{value} !!! this never happens !!!"
      yield value
    end
    puts 'Outer leaving func'
  end
end

outer = Outer.new
outer.func do |value|
  puts "      Script received #{value}"
end

$ ruby subclassed.rb
Outer entered func
  Inner entered func
      Script received 1
      Script received 2
      Script received 3
  Inner leaving func
C:/Source/temp/rubytest/subclassed.rb:14:in `func': undefined method `func' for nil:NilClass (NoMethodError)
        from C:/Source/temp/rubytest/subclassed.rb:23:in `<main>'

但是,如果我使用封装,一切都按预期工作:

# encapsulated.rb

class Inner
  def func
    puts '  Inner entered func'
    yield 1
    yield 2
    yield 3
    puts '  Inner leaving func'
  end
end

class Outer
  def initialize
    @inner = Inner.new # (use encapsulation)
  end
  def func
    puts 'Outer entered func'
    @inner.func do |value| # (use encapsulation)
      puts "    Outer received #{value}"
      yield value
    end
    puts 'Outer leaving func'
  end
end

outer = Outer.new
outer.func do |value|
  puts "      Script received #{value}"
end

$ ruby encapsulated.rb
Outer entered func
  Inner entered func
    Outer received 1
      Script received 1
    Outer received 2
      Script received 2
    Outer received 3
      Script received 3
  Inner leaving func
Outer leaving func

作为实验,我将def func更改为def func(&callback),将yield 1更改为callback.call(1),但我的行为相同。

有一些现有的帖子处理子类和超类,还有一些处理收益。但是,我无法找到有关此特定问题的任何内容。这是我第一次真正对Ruby在很长一段时间里所做的事情感到惊讶!有人有什么想法吗?

1 个答案:

答案 0 :(得分:2)

class Outer < Inner
  def func(&block)
    puts "outer entered func"
    super do |value|
      puts "   Outer received #{value}"
      block.call(value)
    end
    puts "Outer leaving func"
  end
end

我正在使用&block传递块,然后在父方法的上下文中调用块。另外,只需使用super代替super.func来调用父方法。

<强>输出:

o = Outer.new
o.func do |val|
  puts "   Script received #{val}"
end
outer entered func
  Inner entered func
   Outer received 1
   Script received 1
   Outer received 2
   Script received 2
   Outer received 3
   Script received 3
  Inner leaving func
Outer leaving func