替换Ruby中的to_s方法.不打印出所需的字符串

Jwa*_*622 2 ruby class

所以,我刚刚开始学习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方法来获取玩家的字符串表示.对?

Fre*_*ung 6

当考虑到不是字符串或数组参数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最终使用的东西.