Ruby: .+方法是如何在内部工作的?



假设我创建了一个对象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

相关内容

  • 没有找到相关文章

最新更新