嵌套类如何在Ruby中访问外部类中的方法?

时间:2011-02-04 22:20:59

标签: ruby macruby

def class A
  def a
    raise "hi" #can't be reached
  end

  class B
    def b
      a() #doesn't find method a.
    end
  end
end

我想从b调用a并引发异常。我怎么能?

7 个答案:

答案 0 :(得分:27)

Ruby没有嵌套类。

继承行为的唯一方法是通过继承。

如果希望代码有效,则需要使用支持嵌套类的语言。虽然这是令人难以置信的整洁而强大的功能,但遗憾的是我只知道两种具有嵌套类的语言:

我不知道其他任何人。

Java有一个名为嵌套类的构造,但它们有一些不幸的设计限制。

在上面的示例中,嵌套在B内的A 不是常量 B嵌套在A内。想一想:

C = A::B

现在,该类可在两个名称下使用:A::BC。显而易见的是,C是全局的,而不是嵌套在A中。 (嗯,实际上,C嵌套在Object内,因为实际上还没有全局常量,但这不是重点。)但是CA::B是同一个类,它显然不能同时嵌套而不能嵌套。唯一合乎逻辑的结论是类本身不是嵌套的。

嵌套类的定义特征是方法查找沿着两个维度:向上继承链,向外通过嵌套。 Ruby,就像所有OO语言的99.9%一样,只支持前者。 (在某种意义上,嵌套类不仅继承了它们超类的特性,还继承了它们周围类的特征。)

答案 1 :(得分:11)

这只适用于lulz:

class A
  def a
    puts "hello from a"
  end

  class B
    def b
      Module.nesting[1].new.a()
    end
  end
end

答案 2 :(得分:4)

我通常做这样的事情:

class A
  def a
    puts "hi"
  end

  def createB
    B.new self
  end

  class B
    def initialize(parent)
      @parent=parent
    end

    def b
      @parent.a
    end
  end
end

A.new.createB.b

答案 3 :(得分:3)

如果您希望嵌套类扩展外部类,则执行以下操作:

class Outer

  class Inner < Outer
    def use_outer_method
      outer_method("hi mom!")
    end
  end

  def outer_method(foo)
    puts foo
  end

end

foo = Outer::Inner.new
foo.use_outer_method        #<= "hi mom"
foo.outer_method("hi dad!") #<= "hi dad"

答案 4 :(得分:1)

根据您的具体情况,实际上有一个解决方案,非常简单。 Ruby允许捕获对象未捕获的方法调用。因此,对于您的示例,您可以这样做:

def class A
  def a
    raise "hi" #can't be reached
  end

  class B
    def initialize()
      @parent = A.new
    end

    def b
      a() #does find method a.
    end

    def method_missing(*args)
      if @parent.respond_to?(method)
        @parent.send(*args)
      else
        super
      end
    end
  end
end

那么如果你这样做:

A::B.new().b

你得到:

!! #<RuntimeError: hi>

这可能是一种更简单的方法,可以像SubController一样只处理某些活动,但可以轻松调用基本的控制器方法(你可能希望在初始化程序中将父控制器作为参数发送)。

显然这应该谨慎使用,如果你在整个地方使用它会让人感到困惑,但是简化代码真的很棒。

答案 5 :(得分:0)

a应该是类A的类方法吗?

class A
  def self.a
    raise "hi"
  end
  class B
    def b
      A::a 
    end
  end
end

A::B.new.b

如果你想把它作为一个实例方法,你显然可以在一个实例上调用它,比如A.new.a

答案 6 :(得分:0)

您可以使用parentparent_nameparents之类的方法来获取外部模块,例如:

class A
  def self.a; puts 'a!' end

  class B
    def self.b; parent.a end
  end
end

A::B.b #=> a!