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

时间:2014-10-14 16:11:59

标签: ruby class

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

4 个答案:

答案 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

因此nilplayer1返回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