22
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 并引发异常。我怎样才能?

4

7 回答 7

27

Ruby 没有嵌套类。

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

如果你想让你的代码工作,你需要使用一种支持嵌套类的语言。虽然这是一个非常简洁和强大的功能,但不幸的是,我只知道两种具有嵌套类的语言:

我不知道还有其他的。

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

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

C = A::B

现在,该类有两个名称:A::BC. 应该立即显而易见的是,它C是全局的,而不是嵌套在里面A。(嗯,实际上,C嵌套在 内部Object,因为也没有真正的全局常量,但这不是重点。)但是由于CA::B是同一个类,它显然不能既嵌套又不嵌套。唯一合乎逻辑的结论是类本身没有嵌套。

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

于 2011-02-04T22:39:30.270 回答
13

这仅适用于 lulz:

class A
  def a
    puts "hello from a"
  end

  class B
    def b
      Module.nesting[1].new.a()
    end
  end
end
于 2011-02-05T06:53:31.707 回答
5

我通常会做这样的事情:

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
于 2012-02-19T05:33:57.763 回答
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"
于 2011-05-25T16:46:57.067 回答
2

好吧,根据您的情况,实际上有一个解决方案,一个非常简单的解决方案。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 这样只处理某些活动,但可以轻松调用基本控制器方法的东西(尽管您希望将父控制器作为参数发送到初始化程序中)。

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

于 2015-02-13T03:54:29.597 回答
1

您可以使用ActiveSupport 中的module_parent,module_parent_name​​ ,等方法module_parents来获取外部模块,例如:

class A
  def self.a; puts 'a!' end
  
  class B
    def self.b; module_parent.a end # use `parent` if rails < 6.0
  end
end

A::B.b #=> a!
于 2020-03-24T17:03:48.873 回答
0

a应该是 class 的类方法吗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.

于 2011-02-04T22:29:50.420 回答