【问题标题】:What is the object in Ruby's "hello world"?Ruby 的“hello world”中的对象是什么?
【发布时间】:2017-06-14 15:32:53
【问题描述】:

如果在 Ruby 中一切都是对象,那么即使是数学运算符也是应用于对象的方法,当我编写时:

puts "Hello world"

方法是puts,参数是"Hello world",但是对象是什么?

【问题讨论】:

  • 字符串被认为是对象,所以“Hello world”是一个字符串对象
  • "Hello world" 是字符串的一个实例。 String 是 Object 的子类。 Object 的实例是一个对象。 String 的一个实例是一个专门的对象。

标签: ruby oop object methods puts


【解决方案1】:

看跌

要查找方法,您可以调用:

method(:puts)
#=> #<Method: Object(Kernel)#puts>

所以putsKernel 中定义的一个方法,可供每个Object 使用。

内核#puts

puts "Hello world"

其实是

self.puts( String.new("Hello world") )

其中self 是对象main

所以puts "hello world" 是:

  • Kernel#puts方法调用
  • main
  • 使用 String 对象作为参数。

注意事项

注意,如果你执行

self.puts( String.new("Hello world") )

你会得到一个错误:

private method `puts' called for main:Object (NoMethodError)

因为每个 Kernel 方法都对每个 Object 可用,但作为私有方法。你需要:

self.send(:puts, String.new("Hello world") )

测试

另一种检查方法是:

module Kernel
  def my_puts(*args)
    print "Calling Kernel#my_puts on #{self} with #{args}\n"
    print "Now delegating to Kernel#puts on #{self} with #{args} :\n"
    puts(*args)
  end
end

my_puts "Hello world"

它输出:

Calling Kernel#my_puts on main with ["Hello world"]
Now delegating to Kernel#puts on main with ["Hello world"] :
Hello world

看到了吗?一切都是对象,即使它可能看起来不像。

2+3

同样:2+3 实际上是 Integer(2).+( Integer(3) )

【讨论】:

    【解决方案2】:

    如果在 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" 的评估产生。

    但是,这里涉及的对象更多。例如,mainObject 的一个实例,所以Object 也必须存在。 "Hello world"String 的一个实例,String 必须存在。 StringObject 都是类,即作为 Class 类的实例的对象,所以 Class 必须存在。 Object 的超类是 BasicObjectClass 的超类是 ModuleObject 混入Kernel(这是Module 类的一个实例)。 Kernel#puts 返回nil,它是NilClass 的一个实例。 Kernel#puts 只是一个辅助方法,它通过调用 $stdout.puts 委托给 IO#puts

    所以,除了main"Hello world"之外,至少还涉及到以下对象:nilNilClassStringClass、@987654364 @、ObjectKernelBasicObjectIO,以及分配给全局变量$stdoutIO对象,代表你的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 个对象参与执行,嗯,基本上是一个什么都不做的空程序。

    【讨论】:

    • 非常有趣的答案,一如既往。谢谢!
    • 是的,我的意思是“每个值”意义上的“一切”,以及“接收者对象是什么”。我从布鲁斯·泰特 (Bruce Tate) 的优秀著作《七周内的七种语言》中汲取了“一切”的措辞。感谢您的回答。
    • blocks aren't objects他们不是只是伪装了Procs吗?
    • @ericduminil 不,块不是对象,它们只是一段字节码。除非您使用&amp; 实现该块,否则不会创建任何对象。您可以使用我的pry-objects gem 来验证这一点。
    • @akuhn:谢谢。您的宝石看起来不错,我会深入研究一下。
    【解决方案3】:

    "Hello world" 是字符串对象,定义为作为 puts 方法的参数的字面常量

    puts "Hello world"其实是一种简单的方法

    puts myFoo
    

    myFoo 必须是一个有效的对象...在你的情况下是 myFoo = "Hello world"

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-12
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多