假设我创建了一个对象a,并给它一个方法。to_i,为什么这个对象不能被添加到一个整数?
>> a = Object.new
=> #<Object:0x0000000006cfa9d0>
?> def a.to_int
?> 42
>> end
=> :to_int
>> 3 + a
(irb):5:in `+': Object can't be coerced into Integer (TypeError)
from (irb):5:in `<main>'
感谢Stefan,它工作了!
irb(main):010:1* def a.coerce other
irb(main):011:1* [other, 42]
irb(main):012:0> end
=> :coerce
irb(main):013:0> 1 + a
=> 43
向对象添加整数可以通过实现+
来实现,例如:
class Foo
def initialize(value)
@value = value
end
def to_i
@value
end
def +(other)
Foo.new(to_i + other.to_i)
end
end
Foo.new(5) + 4
#=> #<Foo:0x00007fbd22050640 @value=9>
为了将Foo
的实例添加到一个整数,您还必须实现coerce
,它将左边的值作为参数并返回一个数组,其中两个值都转换为Foo
实例,例如:
class Foo
# ...
def coerce(other)
[Foo.new(other.to_i), self]
end
end
这给你:
4 + Foo.new(5)
#=> #<Foo:0x00007fba600e3e28 @value=9>
Numeric
的文档包含另一个示例。
内部,如果参数不是整数,Integer#+
会调用coerce
: (C代码)
VALUE
rb_int_plus(VALUE x, VALUE y)
{
if (FIXNUM_P(x)) {
return fix_plus(x, y);
}
else if (RB_TYPE_P(x, T_BIGNUM)) {
return rb_big_plus(x, y);
}
return rb_num_coerce_bin(x, y, '+');
}
rb_num_coerce_bin
先调用coerce
,然后对返回值调用二进制运算符+
。
在Ruby中应该是:(简化)
class Integer
def +(other)
if other.is_a?(Integer)
# ...
else
x, y = other.coerce(self)
x + y
end
end
end
您仍然需要调用to_int
方法,否则解释器如何知道您想要做什么?
>> 3 + a.to_int
Ruby不支持自动转换
>> 3 + "5"
这将给出相同的错误,即使"5"有一个非常好的to_i方法。顺便说一句。为了保持一致性,ruby中的to int方法通常被称为to_i
。