让我们玩得开心
2 + 5 = 7
2.class = Integer
5.class = Integer
'2' + '5' = '25'
'2'.class = String
'5'.class = String
所以整数 + 是数字加号
并且字符串+ 是串联等效的
...但是为什么呢?
您需要了解的是,Ruby 中的 Integer 是一个对象,而 String 也是一个对象。所有对象(在任何 OOP 语言中)都有可以调用它们的方法:
2.public_methods
=> [:%, :&, :*, :+, :-, :/, :<, :>, :^, :|, :~, :-@, :**, :<=>, :<<, :>>, :<=, :>=, :==, :===, :[], :inspect, :size, :succ, :to_int, :to_s, :to_i, :to_f, :next, :div, :upto, ....and the list goes on
'2'.public_methods
=> [:include?, :%, :*, :+, :to_c, :count, :unicode_normalize, :unicode_normalize!, :unicode_normalized?, :partition, :unpack, :unpack1, :sum, :next, ...and the list goes on
所以实际上当你这样做时:
2 + 5
'2' + '5'
你实际上是在调用一个方法.+
2.+(5)
'2'.+('5')
但实际上在 OOP 语言中调用方法实际上是向对象“发送”消息:
2.send(:+, 5)
'2'.send(:+, '5')
不管怎样,
您需要意识到的一件事是,如果您将不同的对象混合在一起,例如:
'2' + 5
# => TypeError: no implicit conversion of Integer into String
2 + '5'
# => TypeError: String can't be coerced into Integer
Ruby 会通过引发错误来保护您。以防万一您或您的同事在您的代码中做一些愚蠢的事情
但没有什么能阻止您将一种对象类型转换为另一种对象类型
'2'.to_i + 5
#=> 7
2 + '5'.to_i
# => 7
'2' + 5.to_s
# => '25'
完全 OOP 语言(如 Ruby)的另一个有趣部分是您可以使用 + 方法创建自己的对象
class SafePlus
def initialize(first_value)
@first_value = first_value
end
def +(other_value)
@first_value.to_i + other_value.to_i
end
end
SafePlus.new(2) + '5'
# => 7
SafePlus.new("5") + "107"
# => 112
您还可以覆盖 String 类或 Integer 类的原始实现,以便所有相应的对象都将这样:
module MyIntegerFix
def +(other)
super(other.to_i)
end
end
Integer.prepend(MyIntegerFix)
2 + "5"
# => 7
但看在上帝的份上,不要那样做!
为了让你完全困惑,这是一个令人兴奋的场景,你实际上可以覆盖单个对象
a = "5"
a + "2"
# => "52"
def a.+(other)
self.to_i + other.to_i
end
a + "2"
# => 7
#but
"5" + "2"
# => "52"
所以在这种情况下,我们只是覆盖了一个对象,a 对象不是整个 String 类。
您将无法以这种方式覆盖 Integer 对象,因为它们是 Singletons ...无法在单个对象基础上覆盖的东西