Ruby 1.9中的ARGF.class是什么?

30
在 Ruby 1.8.7 中,文档没有在类和模块下列出 ARGF,而且 ARGF 不是一个类或者模块。
ARGF.class # => Object

在Ruby 1.9.3中,文档ARGF列在了类和模块下,但我看到这个:

ARGF.class # => ARGF.class
ARGF.superclass # => NoMethodError: undefined method `superclass' for ARGF:ARGF.class
ARGF.class.superclass # => Object
  • 为什么Ruby 1.9文档将ARGF标记为一个类,而实际上它是另一个东西?或者它们是相同的东西吗?
  • ARGF.class是元类、虚类、单例类还是其他什么?

请查看 https://groups.google.com/forum/?fromgroups=#!topic/ruby-talk-google/ADQI5rhuJms。他们对这个问题提出了一些想法。 - Josh
4个回答

27

ARGF 是用 C 实现的,它可以做一些奇怪的事情。在那里首先定义了 ARGF 类。在 Ruby 中没有将其设置为任何常量,但其名称设置为 "ARGF.class"。 然后,ARGF 常量被设置为该类的一个实例。

rb_cARGF = rb_class_new(rb_cObject);
rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
/* ... */
argf = rb_class_new_instance(0, 0, rb_cARGF);
rb_define_global_const("ARGF", argf);

这里有一段 Ruby 代码,大致做了同样的事情。

argf_class = Class.new
def argf_class.name
  "ARGF.class"
end
argf = argf_class.new
ARGF = argf

在 Ruby 中看起来不太合理,但在 C 中是可以的。尽管如此,我认为类应该设置为 ARGFClass,就像 NilClassTrueClassFalseClass 一样,这样就不会让人产生困惑。

我不知道更改的历史。我认为 Ruby 核心开发人员想要将 ARGF 放入文档中,而这是最简单的方法。(RDoc 无法显示单例对象的文档)


+1 如果能找到并展示C实现。我仍然想知道1.8和1.9之间实际上发生了什么变化。1.8的方法很有道理,但我不知道1.9现在正在发生什么。我无法想象Ruby开发人员会故意引入令人困惑的东西,但不知何故,我一直没有找到一个清晰的语义描述。 - Ray Toal
我同意它应该被命名为 ARGFClass - sawa
@Seymon 已经接受,但仍有一个有趣的变化。Ruby 1.8.7将 ARGF.class 显示为 Object,但现在它已经不同了。我猜这里需要比较 C 实现。对于尝试引入单例类对象描述的文档编写者的好假设。 - Ray Toal
ARGF.class不是Object,因为它现在是一个特殊类的实例。它的名称在第二行明确设置为“ARGF.class”。否则,我猜它会是类似于#Class:0x007ffc55120d50的东西。 - Simon Perepelitsa

7
这句话的意思是,ARGF不是一个类或模块。
class ARGF
end
# => TypeError: ARGF is not a class

module ARGF
end
# => TypeError: ARGF is not a module

文档将ARGF列在类下,但除此之外,它并没有说明它是一个类。可能,ARGF不打算作为类处理,文档将其列为类是错误的,这是文档的错误。
看起来ARGF是某个类中唯一的实例,缺少字面量,并且唯一引用它的方法是调用ARGF.class
ARGF.class.class
# => Class

ARGF.class.ancestors
# => [ARGF.class, Enumerable, Object, Kernel, BasicObject]

通常类和它的实例之间的关系也适用于 ARGF.classARGF
ARGF.is_a?(ARGF.class)
# => true

ARGF.kind_of?(ARGF.class)
# => true

4
如果我们捕获对象并仅使用纯Ruby查看它们,我们可以看到一些东西:
1.9.3 (Object#main):0 > ARGFClass = ARGF.class                                                                                                                                      
=> ARGF.class
1.9.3 (Object#main):0 > ARGFClass.name                                                                                                                                              
=> "ARGF.class"
1.9.3 (Object#main):0 > ARGFClass.class                                                                                                                                             
=> Class
1.9.3 (Object#main):0 > ARGFClass.superclass                                                                                                                                        
=> Object
1.9.3 (Object#main):0 > ARGFClass.ancestors                                                                                                                                         
=> [ARGF.class,
    Enumerable,
    Object,
    JSON::Ext::Generator::GeneratorMethods::Object,
    PP::ObjectMixin,
    Kernel,
    BasicObject]

由于某种原因,开发者明确将class.name的值设置为返回ARGF.class,这通常是不常见的,但在Ruby内部用于不应直接访问的常量。
我们可以像任何其他类一样使用ARGFClass实例化对象。这意味着它是一个真正的Ruby类:
1.9.3 (Object#main):0 > argfinstance = ARGFClass.new                                                                                                                                
=> ARGF
1.9.3 (Object#main):0 > argfinstance.inspect                                                                                                                                        
=> "ARGF"

当你调用 #new 方法时,它不仅仅是返回单例对象:

1.9.3 (Object#main):0 > argfinstance == ARGF                                                                                                                                        
=> false
1.9.3 (Object#main):0 > argfinstance.object_id                                                                                                                                      
=> 70346556507420
1.9.3 (Object#main):0 > ARGF.object_id                                                                                                                                              
=> 70346552343460

Ruby开发人员有意将ARGF.class命名,以使其无法直接通过名称引用,但它是一个真正的类,ARGF是一个真正的对象。
它具有许多与IO对象相同的方法,实际上是在io.c源文件中定义的。它还混合了可枚举模块,因此支持所有each/inject/map功能。
编辑:文档将ARGF列为一个类。但事实上,它是一个常量,引用了一个奇怪命名的ARGF.class类的单例实例。

参考资料


0

ARGF是一个数组类。 在https://github.com/DouglasAllen/Ruby_core_ri_doc/tree/master/ARGF中可以看到一些例子。 也许不是按名称使用,但只要像使用任何数组一样使用它,您就可以知道如何使用,除了您可以将命令行参数传递给它。尝试添加其他内容以查看会发生什么。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接