如果在 Ruby 中一切都是对象,
这是有点误导的措辞。例如。语法不是对象,块不是对象,条件表达式不是对象。
更好的措辞是:“每个值都是一个对象”。
当我写作时,甚至数学运算符都是应用于对象的方法:
puts "Hello world"
方法是puts,参数是"Hello world",但是对象是什么?
涉及两个对象。我怀疑您真正要问的是“receiver 对象是什么”。 (其实涉及到的对象还很多,但现在让我们关注接收者和参数。)
消息发送总是有一个接收者对象,即你发送消息的对象。如果接收者对象没有显式写出,则隐式假定为self(一个始终计算为“当前对象”的伪变量)。现在,问题是:self 这里是什么(或“谁”)?
顺便说一句,这是您在编写 Ruby 代码时应该问自己的最重要的问题之一。无接收者消息发送到self,实例变量在self 中查找。您应该始终知道哪个对象 self 位于您编写代码的位置。
在这种特殊情况下,当您在 Ruby 主义者所谓的 顶级 上编写代码时,self 是 Ruby 主义者称为 main 的预定义对象。它实际上没有名称,也没有对它的默认引用,但'main' 是当您inspect 或使用to_s 将其转换为字符串时返回的内容:
to_s
#=> 'main'
inspect
#=> 'main'
您已经正确识别的第二个对象:它是 String 对象,由对字符串文字 "Hello World" 的评估产生。
但是,这里涉及的对象更多。例如,main 是Object 的一个实例,所以Object 也必须存在。 "Hello world" 是String 的一个实例,String 必须存在。 String 和 Object 都是类,即作为 Class 类的实例的对象,所以 Class 必须存在。 Object 的超类是 BasicObject。 Class 的超类是 Module。 Object 混入Kernel(这是Module 类的一个实例)。 Kernel#puts 返回nil,它是NilClass 的一个实例。 Kernel#puts 只是一个辅助方法,它通过调用 $stdout.puts 委托给 IO#puts。
所以,除了main和"Hello world"之外,至少还涉及到以下对象:nil、NilClass、String、Class、@987654364 @、Object、Kernel、BasicObject、IO,以及分配给全局变量$stdout的IO对象,代表你的Ruby进程的标准输出流。
这是 12 个对象,它们直接且密切地参与了您的代码 sn-p 的执行。
实际上,即使是一个简单的 Ruby 程序也有更多的对象:
ruby --disable-gems --disable-did_you_mean -e 'p ObjectSpace.count_objects[:TOTAL]'
在我的系统上,这会打印出大约 9780 个对象的数字。现在,其中一些是由ObjectSpace::count_objects 创建的Hash 以及Hash 内部的键和值(例如Symbol 对象:TOTAL),当然还有通过尝试打印创建的String出结果。但这大约是大约 35 个对象,所以仍然有将近 10000 个对象参与执行,嗯,基本上是一个什么都不做的空程序。