为什么Ruby不自动执行to_s?

时间:2022-09-25 18:27:04

I have an author class:

我有一个作者类:

class Author < ActiveRecord::Base
  def to_s
    name
  end
end

Defining to_s allows me to do puts Author.first, but not puts Author.first.rjust(10):

定义to_s允许我做放置Author.first,但不放置Author.first.rjust(10):

NoMethodError: undefined method `rjust' for #<Author:0x21eb5d4>

Wouldn't it be better if Ruby automatically tried to_s before the string method in cases like this? Is there any way to get this behavior?

如果Ruby在这种情况下在字符串方法之前自动尝试to_s,那不是更好吗?有没有办法得到这种行为?

4 个解决方案

#1


First off, no, it wouldn't. I don't want ruby to just say "Hey, maybe this is a string method, let me see if I can run it after running to_s" on an arbitrary object. That being said, there are two solutions to what you want to do:

首先,不,它不会。我不希望ruby只是说“嘿,也许这是一个字符串方法,让我看看我是否可以在任意对象上运行to_s后运行它”。话虽如此,有两种解决方案可以满足您的需求:

If you want to say "On any Author instance, if someone calls a method that it doesn't have, but that String does, then it should magically call to_s", then do this:

如果你想说“在任何作者实例上,如果有人调用了一个它没有的方法,但是那个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

If you want to say "rjust on anything that isn't a String should mean calling to_s first", then:

如果你想说“对任何不是字符串的东西应该首先调用to_s”,那么:

class Object
  def rjust(*a)
    to_s.rjust(*a)
  end
end

(Repeat with other methods as desired; note that this allows you to do things like 86.rjust(10); whether that's a good thing or not may be a matter of taste)

(根据需要重复其他方法;请注意,这可以让你做86.rjust(10)之类的事情;这是否是好事可能是品味问题)

#2


Wouldn't it be better if Ruby automatically tried to_s before the string method in cases like this?

如果Ruby在这种情况下在字符串方法之前自动尝试to_s,那不是更好吗?

You're heading down a slippery slope by asking for a language to "just do what I mean (most of the time)." While it might make sense in many cases, it's bound to foul things up around the edges. In your case, who's to say that rjust isn't a method defined on Author (or one of its superclasses).

通过要求一种语言“只是按照我的意思(大部分时间)”,你正走向一个滑坡。“虽然在许多情况下它可能有意义,但它必然会在边缘附近弄脏。在你的情况下,谁会说rjust不是在Author(或其中一个超类)上定义的方法。

#3


Check out ruby's support for delegation and method forwarding

查看ruby对委派和方法转发的支持

#4


Actually... there IS a method that would do something vaguely similar to this: to_str

实际上......有一种方法会做一些与此类似的东西:to_str

However, it still wouldn't be called implicitly for this particular case. The existence of a to_str method in Ruby is effectively equivalent to saying, "Any method that would normally take a String as a parameter may implicitly convert this object to a String by calling the to_str method." Most methods in the standard library will attempt to use this technique to coerce to String, and a lot of 3rd party libraries do as well.

但是,对于这种特殊情况,它仍然不会被隐式调用。 Ruby中to_str方法的存在实际上等同于说:“任何通常将String作为参数的方法都可以通过调用to_str方法将该对象隐式转换为String。”标准库中的大多数方法都会尝试使用这种技术强制转换为String,而且许多第三方库也会这样做。

In the example you gave, however, it would be absolutely inappropriate for Ruby to detect that an unhandled message was String-like and convert. This would lead to all kinds of errors, bugs, and general misbehavior in a lot of non-String related code, especially any of the code out there like Builder that relies on the normal missing method behavior.

但是,在您给出的示例中,Ruby绝对不适合检测未处理的消息是否类似于String并进行转换。这将导致许多非String相关代码中的各种错误,错误和一般错误行为,尤其是那些像Builder一样依赖于正常缺失方法行为的代码。

#1


First off, no, it wouldn't. I don't want ruby to just say "Hey, maybe this is a string method, let me see if I can run it after running to_s" on an arbitrary object. That being said, there are two solutions to what you want to do:

首先,不,它不会。我不希望ruby只是说“嘿,也许这是一个字符串方法,让我看看我是否可以在任意对象上运行to_s后运行它”。话虽如此,有两种解决方案可以满足您的需求:

If you want to say "On any Author instance, if someone calls a method that it doesn't have, but that String does, then it should magically call to_s", then do this:

如果你想说“在任何作者实例上,如果有人调用了一个它没有的方法,但是那个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

If you want to say "rjust on anything that isn't a String should mean calling to_s first", then:

如果你想说“对任何不是字符串的东西应该首先调用to_s”,那么:

class Object
  def rjust(*a)
    to_s.rjust(*a)
  end
end

(Repeat with other methods as desired; note that this allows you to do things like 86.rjust(10); whether that's a good thing or not may be a matter of taste)

(根据需要重复其他方法;请注意,这可以让你做86.rjust(10)之类的事情;这是否是好事可能是品味问题)

#2


Wouldn't it be better if Ruby automatically tried to_s before the string method in cases like this?

如果Ruby在这种情况下在字符串方法之前自动尝试to_s,那不是更好吗?

You're heading down a slippery slope by asking for a language to "just do what I mean (most of the time)." While it might make sense in many cases, it's bound to foul things up around the edges. In your case, who's to say that rjust isn't a method defined on Author (or one of its superclasses).

通过要求一种语言“只是按照我的意思(大部分时间)”,你正走向一个滑坡。“虽然在许多情况下它可能有意义,但它必然会在边缘附近弄脏。在你的情况下,谁会说rjust不是在Author(或其中一个超类)上定义的方法。

#3


Check out ruby's support for delegation and method forwarding

查看ruby对委派和方法转发的支持

#4


Actually... there IS a method that would do something vaguely similar to this: to_str

实际上......有一种方法会做一些与此类似的东西:to_str

However, it still wouldn't be called implicitly for this particular case. The existence of a to_str method in Ruby is effectively equivalent to saying, "Any method that would normally take a String as a parameter may implicitly convert this object to a String by calling the to_str method." Most methods in the standard library will attempt to use this technique to coerce to String, and a lot of 3rd party libraries do as well.

但是,对于这种特殊情况,它仍然不会被隐式调用。 Ruby中to_str方法的存在实际上等同于说:“任何通常将String作为参数的方法都可以通过调用to_str方法将该对象隐式转换为String。”标准库中的大多数方法都会尝试使用这种技术强制转换为String,而且许多第三方库也会这样做。

In the example you gave, however, it would be absolutely inappropriate for Ruby to detect that an unhandled message was String-like and convert. This would lead to all kinds of errors, bugs, and general misbehavior in a lot of non-String related code, especially any of the code out there like Builder that relies on the normal missing method behavior.

但是,在您给出的示例中,Ruby绝对不适合检测未处理的消息是否类似于String并进行转换。这将导致许多非String相关代码中的各种错误,错误和一般错误行为,尤其是那些像Builder一样依赖于正常缺失方法行为的代码。