【问题标题】:Get Ruby class name without class method获取没有类方法的 Ruby 类名
【发布时间】:2012-04-16 15:42:33
【问题描述】:

如何在 Ruby 中获取 BasicObject 实例的类名?例如,假设我有这个:

class MyObjectSystem < BasicObject
end
puts MyObjectSystem.new.class

我怎样才能使这段代码成功?

编辑:我发现 Object 的实例方法 class 被定义为 return rb_class_real(CLASS_OF(obj));。有什么方法可以从 Ruby 中使用它?

【问题讨论】:

  • 你能举一个更具体的例子来说明你正在尝试做什么吗?您是在问“如果我有一个继承自 BasicObject 的类 Foo,有没有办法确定该类的实例是 'Foo' 而不是 BasicObject”?不知道你在问什么。
  • 实际上,没错!更改帖子以澄清
  • 为什么不能使用#class方法?
  • @JoshuaCheek 因为#class 是在Object 上定义的,而不是我的类继承自的BasicObject(我确定我不想使用Object)
  • BasicObject的重点是没有有很多方法。为什么需要或想要继承 BasicObject 而不是 Object?

标签: ruby oop class object ruby-1.9.3


【解决方案1】:

我花了一些时间玩 irb 并想出了这个:

class BasicObject
  def class
    klass = class << self; self; end # get the object's singleton class
    klass.superclass # the superclass of an object's singleton class is that object's class
  end
end

这将为从 BasicObject 继承的任何对象提供一个您可以调用的 #class 方法。

编辑

在 cmets 中要求的进一步解释:

假设您有对象obj,它是类Foo 的一个实例。除了Foo 的父类中定义的方法之外,obj 还从类Foo 中定义的方法中获取其实例方法,依此类推。 Ruby 允许您直接在对象上定义方法,这些方法只能由特定对象访问,就像这样

obj = Foo.new
def obj.hello
  puts "hello"
end

obj.hello  #=> hello

other_obj = Foo.new
other_obj.hello  #=> Method missing error

您可以这样做的原因是因为每个对象都有一个称为单例类(或有时称为特征类)的东西,您实际上是在其上定义方法。这个单例类实际上存在于对象的实际类之下的对象的继承链中。这使得对象的实际类(在本例中为 Foo)成为对象的单例类的超类。

您在答案中看到的class &lt;&lt; self 行是一种特殊语法,用于输入对象的单例类的范围。所以在上面的例子中,你也可以像这样在对象的单例类中定义一个方法

class << obj
  def goodbye
    puts "goodbye"
  end
end

obj.goodbye  #=> goodbye

所以class &lt;&lt; self; self; end 行打开对象的单例类(无论对象当前是self)然后返回selfself 现在已成为单例类),然后可以将其分配给一个变量随心所欲。

如果您想更好地解释这一切,我建议您阅读Metaprogramming Ruby。它肯定会让您更好地理解整个 Ruby 对象模型。

【讨论】:

  • 太棒了。我想了解它为什么以及如何工作。你能提供更深入的解释吗?
  • @MatheusMoreira 没问题!我编辑了答案以提供一些额外的解释。它可能仍然有点令人困惑,但希望能为您提供足够的信息来深入了解并了解更多信息!
  • 谢谢,很好的解释!我仍然很难理解单例类在继承树中的位置。 this diagram 是否准确捕捉到关系?
  • 不完全。对象直接从其单例类继承,而单例类直接从对象的真实类继承。这是一个简单的链,看起来像:object
  • 再次感谢!我从来没有考虑过,因为Object#class 返回对象的实际类,即使层次结构中有一个单例类。如this article 中所述,class 方法simply skips it。伙计,这改变了我以为我知道的一切!
【解决方案2】:

我必须在几分钟后离开,所以我无法自己测试它,但您似乎可以制作一个单独的模块,使用 ffi 从 libruby 调用 rb_class_real。如果我有更多的时间,我会先测试它,但还没有人回答,我不想让你完全冷落。

【讨论】:

  • 好的,我会调查的。谢谢!但是你知道纯 Ruby 方式吗?那真是太好了。
【解决方案3】:

基于 Jeff Smith 的answer,无需修改BasicObject即可:

class << object; self; end.superclass

其中object 是您想要其类的对象的实例,即,

irb(main):001:0> object = BasicObject.new
(Object doesn't support #inspect)
=> 
irb(main):002:0> class << object; self; end.superclass
=> BasicObject

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-23
    • 2012-12-25
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多