Ruby: .+ 方法在内部是如何工作的?
Ruby: How ist the .+ method working internally?
假设我创建了一个对象 a 并给它一个方法。to_i,为什么这个对象不能添加到一个 Integer 中?
>> 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
你仍然需要调用 to_int
方法解释器怎么知道你想做什么?
>> 3 + a.to_int
Ruby 不进行自动转换。
>> 3 + "5"
这会产生同样的错误,即使“5”有一个非常好的 to_i 方法。顺便提一句。 ruby 中的 to int 方法通常称为 to_i
以防你想保持一致性。
可以通过实现 +
来实现向对象添加整数,例如:
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
它将左侧值作为参数, returns 一个数组两个值都转换为 Foo
个实例,例如:
class Foo
# ...
def coerce(other)
[Foo.new(other.to_i), self]
end
end
这给你:
4 + Foo.new(5)
#=> #<Foo:0x00007fba600e3e28 @value=9>
Numeric
的文档包含另一个示例。
在内部,如果参数不是整数,coerce
由 Integer#+
调用:(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
假设我创建了一个对象 a 并给它一个方法。to_i,为什么这个对象不能添加到一个 Integer 中?
>> 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
你仍然需要调用 to_int
方法解释器怎么知道你想做什么?
>> 3 + a.to_int
Ruby 不进行自动转换。
>> 3 + "5"
这会产生同样的错误,即使“5”有一个非常好的 to_i 方法。顺便提一句。 ruby 中的 to int 方法通常称为 to_i
以防你想保持一致性。
可以通过实现 +
来实现向对象添加整数,例如:
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
它将左侧值作为参数, returns 一个数组两个值都转换为 Foo
个实例,例如:
class Foo
# ...
def coerce(other)
[Foo.new(other.to_i), self]
end
end
这给你:
4 + Foo.new(5)
#=> #<Foo:0x00007fba600e3e28 @value=9>
Numeric
的文档包含另一个示例。
在内部,如果参数不是整数,coerce
由 Integer#+
调用:(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