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

发布于 2024-10-15 17:24:50 字数 188 浏览 5 评论 0原文

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 并引发异常。我该怎么办?

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

I want to invoke a from b and raise the exception. How can I?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

_畞蕅 2024-10-22 17:24:50

Ruby 没有嵌套类。

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

如果您希望代码正常工作,则需要使用支持嵌套类的语言。虽然这是一个令人难以置信的简洁而强大的功能,但不幸的是,我只知道两种具有嵌套类的语言:

我不知道还有其他的。

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

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

C = A::B

现在,该类有两个名称:A::BC。很明显,C 是全局的,并且不嵌套在 A 内。 (嗯,实际上,C 嵌套在 Object 中,因为也没有真正的全局常量,但这不是重点。)但是自从 C code> 和 A::B 是同一个类,显然不能既嵌套又不嵌套。唯一合乎逻辑的结论是类本身不是嵌套的。

嵌套类的定义特征是方法查找沿着两个维度进行:沿着继承链向上,以及通过嵌套向外查找。与 99.9% 的所有 OO 语言一样,Ruby 只支持前者。 (从某种意义上说,嵌套类不仅继承其超类的功能,还继承其周围类的功能。)

Ruby doesn't have nested classes.

The only way to inherit behavior is, well, via inheritance.

If you want your code to work, you need to use a language which supports nested classes. While this is an incredibly neat and powerful feature, I unfortunately know of only two languages that have nested classes:

I don't know of any other.

Java has a construct called nested classes, but they have some unfortunate design limitations.

In your example above, it's not the class B that is nested inside A, it is the constant B that is nested inside A. Think about this:

C = A::B

Now, the class is available under two names: A::B and C. It should be immediately obvious that C is global and not nested inside A. (Well, actually, C is nested inside Object, because there aren't really global constants either, but that's beside the point.) But since C and A::B are the same class, it obviously cannot be both nested and not nested. The only logical conclusion is that the class itself isn't nested.

The defining feature of nested classes is that method lookup goes along two dimensions: up the inheritance chain, and outwards through the nesting. Ruby, like 99.9% of all OO languages, only supports the former. (In some sense, nested classes inherit not only the features of their superclass, but also the features of their surrounding class.)

删除会话 2024-10-22 17:24:50

这只是为了好玩:

class A
  def a
    puts "hello from a"
  end

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

This is just for the lulz:

class A
  def a
    puts "hello from a"
  end

  class B
    def b
      Module.nesting[1].new.a()
    end
  end
end
怪我闹别瞎闹 2024-10-22 17:24:50

我通常会做这样的事情:

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

I typically do something like this:

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
葬花如无物 2024-10-22 17:24:50

如果您希望嵌套类扩展外部类,请这样做:

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"

If you want then nested class to extend the outer class, then do so:

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"
二智少女 2024-10-22 17:24:50

嗯,根据您的具体情况,实际上有一个解决方案,而且是一个非常简单的解决方案。 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 的东西,它只处理某些活动,但可以轻松调用基本控制器方法(您可能想要发送不过,父控制器作为初始化程序中的参数)。

显然,应该谨慎使用它,如果你到处使用它,它真的会让人感到困惑,但它对于简化你的代码来说确实很棒。

Well depending on your circumstances there is actually a solution, a pretty easy one at that. Ruby allows the catching of method calls that aren't captured by the object. So for your example you could do:

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

So then if you do this:

A::B.new().b

you get:

!! #<RuntimeError: hi>

It is probably an easier way to make something like a SubController that only handles certain activities, but can easily call basic controller methods (You would want to send in the parent controller as an argument in the initializer though).

Obviously this should be used sparingly, and it can really get confusing if you use it all over the place, but it can be really great to simplify your code.

玩心态 2024-10-22 17:24:50

您可以使用 ActiveSupport 中的 module_parentmodule_parent_namemodule_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!

You can use methods like module_parent, module_parent_name, module_parents from ActiveSupport to get outer modules, eg.:

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!
稚然 2024-10-22 17:24:50

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

Was a supposed to be a class method for class A?

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

A::B.new.b

If you want to keep it as an instance method, you'll obviously have call to it on an instance, like for example A.new.a.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文