所以,我刚刚开始学习Ruby,我在我的类中包含了一个to_s方法,这样我就可以简单地将Object传递给puts方法,让它返回的不仅仅是Object ID。我犯了一个错误并将其定义为:
def to_s
puts "I'm #{@name} with a health of #{@health}."
end
而不是:
def to_s
"I'm #{@name} with a health of #{@health}."
end
所以,当我在使用第一个代码块时执行此操作:
player1 = Player.new("larry")
puts player1
当我执行上面两行代码而不仅仅是字符串时,我得到一个对象ID和一个字符串。为什么是这样?我得到了这个输出:
I'm Larry with a health of 90.
#<Player:0x007fca1c08b270>
我试图想一想为什么程序的第一个版本不只是将字符串打印到控制台,而是返回对象ID和字符串。我认为当我将对象传递给puts时,所发生的一切就是puts转向并调用to_s方法来获取玩家的字符串表示。正确?
答案 0 :(得分:6)
当给定的参数不是字符串或数组puts
时,调用rb_obj_as_string
将其参数转换为字符串(参见rb_io_puts)
如果您通过ruby代码库搜索rb_obj_as_string(我发现http://rxr.whitequark.org对此有用),您可以将其视为<{3}}
VALUE rb_obj_as_string(VALUE obj)
{
VALUE str;
if (RB_TYPE_P(obj, T_STRING)) {
return obj;
}
str = rb_funcall(obj, id_to_s, 0);
if (!RB_TYPE_P(str, T_STRING))
return rb_any_to_s(obj);
if (OBJ_TAINTED(obj)) OBJ_TAINT(str);
return str;
}
简而言之:
to_s
rb_any_to_s
并返回该字符串。 rb_any_to_s
是实现默认&#34;类名和id&#34;您将看到的结果:对于任何对象,它都会返回#<ClassName: 0x1234567890abcdef>
返回您的代码,当您运行puts player1
时,它会调用rb_obj_as_string
将您的播放器转换为字符串。
首先调用to_s
方法,该方法使用puts
输出您的消息。然后,您的方法返回nil(因为puts
始终返回的内容)因此ruby调用rb_any_to_s
,这就是最外层puts
最终使用的内容。
答案 1 :(得分:1)
那是因为puts
返回nil,to_s
的版本也是如此:
def to_s
puts "I'm #{@name} with a health of #{@health}."
end
使用puts player1
,调用player1.to_s
方法,打印字符串&#34;我&#39; m ...&#34;,但返回值是{{ 1}}在puts
内调用to_s
。
因此nil
是player1
返回nil的对象,因此最后to_s
打印继承的puts player1
方法的结果。
答案 2 :(得分:1)
体验规则:如果to_s的结果不是String,则ruby返回默认值。
规则的应用: puts()返回nil,这意味着你的to_s方法返回nil,而nil不是String,所以ruby返回默认值。
另一个例子:
class Object
def inspect
'obj-inspect'
end
def to_s
'obj-to_s'
end
end
class Dog
def inspect
'dog-inspect'
end
def to_s
nil
end
end
puts Dog.new
--output:--
#<Dog:0x1001b6218>
一旦to_s无法返回String,ruby就不会沿着方法查找路径继续调用另一个to_s方法。这有点道理:找到了方法,所以不需要在父类中查找该方法。 ruby也不会调用inspect()来获得结果。
默认来自哪里?我认为ruby必须直接调用Object#to_s方法,这是一个用C语言编写的方法 - 从而绕过了ruby的方法覆盖机制。
答案 3 :(得分:0)
使用puts
的第一个示例将写入stdout并返回nil。它实际上并不返回String。
第二个示例返回一个String。
如果您想写入控制台,但您还需要返回值。
#or put it in a variable first and return that after you print it
def to_s
puts "I'm #{@name} with a health of #{@health}."
"I'm #{@name} with a health of #{@health}."
end