我有一个作者类:
class Author < ActiveRecord::Base
def to_s
name
end
end
定义to_s
允许我执行puts Author.first
,但不能puts Author.first.rjust(10)
:
NoMethodError: undefined method `rjust' for #<Author:0x21eb5d4>
如果像这样的情况下Ruby在字符串方法之前自动尝试to_s
,那会不会更好?有没有办法解决这个问题?
答案 0 :(得分:18)
首先,不,它不会。我不希望ruby只是说“嘿,也许这是一个字符串方法,让我看看我是否可以在任意对象上运行to_s
后运行它。话虽这么说,你想做的事情有两种解决方案:
如果你想说“在任何Author
个实例上,如果有人调用了一个它没有的方法,但是String
会这样做,那么它应该神奇地调用to_s
” ,然后这样做:
class Author < ActiveRecord::Base
def to_s
name
end
def method_missing(s, *a)
x = to_s
if x.respond_to? s then
return x.send(s, *a)
else
super
end
end
end
如果你想对任何不是字符串的任何内容说“rjust
应该首先调用to_s
”,那么:
class Object
def rjust(*a)
to_s.rjust(*a)
end
end
(根据需要重复其他方法;请注意,这可以让您执行86.rjust(10)
之类的事情;这是否是好事可能是品味问题)
答案 1 :(得分:2)
如果像这样的情况下Ruby在字符串方法之前自动尝试to_s会不会更好?
你要求一种语言“只是做我的意思(大部分时间)”,这是一个滑坡。“虽然在许多情况下它可能有意义,但它必然会在边缘附近弄脏东西。在你的情况下,谁说 rjust 不是在Author(或其中一个超类)上定义的方法。
答案 2 :(得分:2)
答案 3 :(得分:1)
实际上......有一种方法可以做一些与此类似的事情:to_str
但是,对于这种特殊情况,它仍然不会被隐式调用。 Ruby中存在to_str
方法实际上等同于说:“通常将String作为参数的任何方法都可以通过调用to_str
方法将该对象隐式转换为String。”标准库中的大多数方法都会尝试使用这种技术来强制转换为String,而且许多第三方库也会这样做。
但是,在您给出的示例中,Ruby检测到未处理的消息是类似字符串并进行转换是绝对不合适的。这将导致许多非String相关代码中的各种错误,错误和一般错误行为,尤其是那些像Builder一样依赖于正常缺失方法行为的代码。