在Ruby中替换to_s方法。 不打印出所需的字符串
所以,我刚刚开始学习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. #
我试图考虑为什么程序的第一个版本不只是打印出字符串到控制台,而是返回对象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; }
简而言之:
- 如果参数已经是一个字符串,则直接返回
- 调用
to_s
- 如果结果不是字符串,则调用
rb_any_to_s
并返回该字符串。
rb_any_to_s
实现了您正在看到的默认“类名和ID”结果:对于任何对象,它返回一个forms为#
的字符串#
回到你的代码,当你运行puts player1
它会调用rb_obj_as_string
将你的玩家转换成一个字符串。
这首先调用你的to_s
方法,它使用puts
来输出你的消息。 然后你的方法返回nil(因为这就是总是返回的东西)所以ruby调用rb_any_to_s
,这就是最外面的rb_any_to_s
最终使用的东西。
这是因为puts
返回nil, to_s
那个版本也是to_s
:
def to_s puts "I'm #{@name} with a health of #{@health}." end
使用puts player1
, player1.to_s
方法,打印字符串“我是……”,但返回值是to_s
内的puts
调用,即nil
。
因此, player1
是一个对象,其中to_s
返回nil,因此puts player1
放在最后打印inheritance的to_s
方法的结果。
Experiential Rule:如果to_s的结果不是String,则ruby返回默认值。
Rule: 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:-- #
一旦to_s无法返回String,ruby就不会沿着方法查找路径继续调用另一个to_s方法。 这有点道理:找到了方法,所以不需要在父类中查找该方法。 ruby也不会调用inspect()来获得结果。
默认来自哪里? 我认为ruby必须直接调用Object#to_s方法,这是一个用C语言编写的方法 – 从而绕过了ruby的方法覆盖机制。
使用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