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にはネストされたクラスがありません。

振る舞いを継承する唯一の方法は、まあ、継承を介することです。

コードを機能させるには、ネストされたクラスをサポートする言語を使用する必要があります。これは非常に優れた強力な機能ですが、残念ながら、ネストされたクラスを持つ2つの言語しか知りません。

私は他に何も知りません。

Javaにはネストされたクラスと呼ばれる構造がありますが、残念ながら設計上の制限がいくつかあります。

上記の例では、内部にネストされているのはクラスBではなく、内部Aにネストされている定数 BですA。これについて考えます:

C = A::B

現在、このクラスはとの2つの名前で利用できます。グローバルであり、内部にネストされていないことはすぐにわかります。(実際には、実際にはグローバル定数も存在しないため、内部にネストされていますが、それは重要ではありません。)しかし、とは同じクラスであるため、ネストすることもネストしないこともできません。唯一の論理的な結論は、クラス自体はネストされていないということです。A::BCCACObjectCA::B

ネストされたクラスの定義機能は、メソッドルックアップが2つの次元に沿って行われることです。継承チェーンの上位と、ネストを介した外部です。Rubyは、すべてのOO言語の99.9%と同様に、前者のみをサポートします。(ある意味で、ネストされたクラスは、スーパークラスの機能だけでなく、周囲のクラスの機能も継承します。)

于 2011-02-04T22:39:30.270 に答える
13

これはちょっとしたことです:

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 に答える
0

aclass のクラス メソッドになるはずだったの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 に答える