Numeric types define a conversion method named coerce.
Numeric operators are written so that if they don’t know the type of
the righthand operand, they invoke the coerce method of the righthand
operand, passing the lefthand operand as an argument.
Consideremos este código:
$ cat coerce.rb require 'point' p = Point.new(2,3) q = 2*p puts q
Puesto que Fixnum no sabe como multiplicarse por un Point,
invoca al método coerce de su argumento
(véase el código de point.rb en la sección
14.1.6).
33 def coerce(other)
34 [self, other]
35 end
36
28 def *(scalar) # Define * to perform scalar multiplication
29 return Point.new(@x*scalar, @y*scalar) if scalar.is_a? Numeric
30 return Point.new(@x*scalar.x, @y*scalar.y) if scalar.is_a? Point
31 end
Transformando la llamada 2*p = 2.*(p)
en p*2 = p.*(2).
Veamos una sesión paso a paso con el depurador:
[09:01]$ ruby -rdebug -I. coerce.rb coerce.rb:1:require 'point' (rdb:1) n coerce.rb:3:p = Point.new(2,3) (rdb:1) n coerce.rb:4:q = 2*p (rdb:1) p p (2,3)En vez de saltar sobre la llamada
n(ext)
entremos en el método usando s(tep):
(rdb:1) s point.rb:34: [self, other]¡Aja! estamos en el código de
coerce:
(rdb:1) where
--> #1 point.rb:34:in `coerce'
#2 coerce.rb:4
(rdb:1) self
(2,3)
(rdb:1) other
2
(rdb:1) s
point.rb:29: return Point.new(@x*scalar, @y*scalar) if scalar.is_a? Numeric
(rdb:1) n
coerce.rb:5:puts q
(rdb:1)
n
(4,6)
The intent of
the coerce method is to convert the argument to the same type as
the object on which the method is invoked, or to convert both objects to
some more general compatible type.
[13] pry(main)> 2.coerce(1.1) => [1.1, 2.0] [14] pry(main)> 2+1.1 => 3.1 [8] pry(main)> require 'rational' => true [19] pry(main)> z = Rational(1,3) => (1/3) [20] pry(main)> 2.coerce(z) => [0.3333333333333333, 2.0] [21] pry(main)> z.coerce(2) => [(2/1), (1/3)] [22] pry(main)> 2+z => (7/3)
Casiano Rodriguez León 2015-01-07