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 endTransformando 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