Ruby:为什么 puts 会调用 to_ary?

标签 ruby metaprogramming method-missing

我正在学习 Ruby 中的元编程,并且正在尝试通过 method_missing 和 define_method 定义缺失的方法。我遇到了一些意想不到的行为,想知道是否有人可以解释这一点。这是我的类(class):

class X
  def method_missing(m, *args, &block)
    puts "method #{m} not found. Defining it."
    self.class.send :define_method, m do
      puts "hi from method #{m}"
    end
    puts "defined method #{m}"
  end  
end

现在,这段代码:

x = X.new

x.some_method
puts
x.some_method
puts
puts x

产生输出:

method some_method not found. Defining it.
defined method some_method

hi from method some_method

method to_ary not found. Defining it.
defined method to_ary
#<X:0x007fcbc38e5030>

我不明白的是最后一部分:为什么 Ruby 在调用 puts 时调用 to_ary?为什么 Ruby 会尝试将我的对象转换为数组来打印它?

我用 Google 搜索并找到了这些相关链接:

这些也讨论了 method_missing 和 to_ary 陷阱,但没有具体说明为什么 puts 会调用 to_ary。

我还应该提到,当我定义一个 to_s 时,行为不会改变,例如

def to_s
  "I'm an instance of X"
end

那么“puts x”的输出是:

method to_ary not found. Defining it.
defined method to_ary
I'm an instance of X

最佳答案

puts$stdout.puts 的同义词。 $stdout 是一个 IO 类,因此请查看 IO.puts 的文档:

Writes the given objects to ios as with IO#print. Writes a record separator (typically a newline) after any that do not already end with a newline sequence. If called with an array argument, writes each element on a new line.

这意味着 puts 方法旨在写入多行输出。因此,它会尝试调用对象上的 to_ary 方法,如果定义了 to_ary,则在新行上打印返回的 Array 的每个元素, else puts 调用 to_s 方法。

to_ary 内部用法在 Ruby 文档中确实没有很好的记录(Matz 在他的The Ruby Programming Language 书中指出了这一点)。

另一方面,printp 方法不调用 to_ary,只调用 to_s

旁注:有趣的是,to_ary 必须返回真正的Array 对象,而不是定义each 方法或其他:

class Test
  def to_ary
    10.downto(1)
  end
end

puts Test.new

#TypeError: can't convert Test to Array (Test#to_ary gives Enumerator)
#        from (irb):28:in `puts'
#        from (irb):28:in `puts'
#        from (irb):28

关于Ruby:为什么 puts 会调用 to_ary?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8960685/

相关文章:

ruby-on-rails - 简单的 Rails 注释添加额外的空白注释

haskell - 在类型化模板 Haskell 中使用约束

python - 元 python : Adding Methods to a Class

Objective-C forwardInvocation :

html - 如何用haml每隔几个div插入一个 block ?

python - Ruby 是否有相当于在 Python 中使用 matplotlib 和 basemap 的功能?

ruby-on-rails - Rails验证或可能的路由错误

python - 基本 Python 元编程 : populating dictionaries?

Erlang 和 method_missing

ruby - 对于未定义的实例变量,Ruby 是否有 method_missing 等价物?