所以,我刚刚开始学习Ruby,我在我的类中包含了一个to_s方法,这样我就可以简单地将Object传递给puts方法,让它返回的不仅仅是Object ID.我犯了一个错误并将其定义为:
def to_s
puts "I'm #{@name} with a health of #{@health}."
end
Run Code Online (Sandbox Code Playgroud)
代替:
def to_s
"I'm #{@name} with a health of #{@health}."
end
Run Code Online (Sandbox Code Playgroud)
所以,当我在使用第一个代码块时执行此操作:
player1 = Player.new("larry")
puts player1
Run Code Online (Sandbox Code Playgroud)
当我执行上面两行代码而不仅仅是字符串时,我得到一个对象ID和一个字符串.为什么是这样?我得到这个输出:
I'm Larry with a health of 90.
#<Player:0x007fca1c08b270>
Run Code Online (Sandbox Code Playgroud)
我试图考虑为什么程序的第一个版本不只是打印出字符串到控制台,而是返回对象ID和字符串.我认为当我将对象传递给puts时,所发生的一切就是puts转向并调用to_s方法来获取玩家的字符串表示.对?
当考虑到不是字符串或数组参数puts
调用rb_obj_as_string
把它的参数转换成字符串(见rb_io_puts)
如果您通过ruby代码库搜索rb_obj_as_string(我发现http://rxr.whitequark.org对此很有用),您可以看到它被定义为
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;
}
Run Code Online (Sandbox Code Playgroud)
简而言之:
to_s
rb_any_to_s
并返回该字符串.rb_any_to_s
是什么实现了你所看到的默认"类名和id"结果:对于任何对象,它返回一个表单的字符串 #<ClassName: 0x1234567890abcdef>
返回到您的代码,当您运行puts player1
它时,调用 rb_obj_as_string
将您的播放器转换为字符串.
这首先调用您的to_s
方法,该方法puts
用于输出您的消息.然后你的方法返回nil(因为那是puts
总是返回的)所以ruby调用rb_any_to_s
,这就是最外层puts
最终使用的东西.