Otra forma de construir objetos es via los métodos
dup
y clone
.
Estos métodos crean un objeto que es una copia del del objeto que recibe el mensaje:
>> a = "hello" => "hello" >> b = a.dup => "hello" >> c = a.clone => "hello" >> [a.__id__, b.__id__, c.__id__] => [2150357800, 2150329860, 2150304120]
clone
hace una copia mas parecida que dup
. Por ejemplo,
conserva el estatus de freeze
del original, cosa que no hace dup
:
>> a = "hello" => "hello" >> a.freeze => "hello" >> a << " world" TypeError: can't modify frozen string >> b = a.clone => "hello" >> b << " world" TypeError: can't modify frozen string >> c = a.dup => "hello" >> c << " world" => "hello world"
clone
incluso preserva los singleton methods, esto es, preserva los métodos individuales
del objeto. Sin embargo, dup
no lo hace.
Un singleton method es un método x
que se añade a un objeto obj
específico. A partir del momento en el que se añade, ese objeto obj
responde el mensaje x
, cosa que no hacen los otros métodos de su clase.
Sigue un ejemplo:
~/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules$ cat -n singletonmethandclone.rb 1 obj = "some object" 2 def obj.printme 3 puts "***<#{self}>***" 4 end 5 6 obj.printme 7 8 b = obj.dup 9 c = obj.clone 10 11 c.printme 12 b.printmeEn la línea 2 añadimos el método
printtime
únicamente al objeto obj
. El objeto clonado
c
también puede hacer printtime
. No así la copia b
obtenida por duplicación:
~/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules$ ruby singletonmethandclone.rb ***<some object>*** ***<some object>*** singletonmethandclone.rb:12: undefined method `printme' for "some object":String (NoMethodError)
clone
y dup
copian las variables de instancia / atributos del objeto original al objeto final
sólo copian las referencias a los valores de esas variables no copian los valores reales: sólo hacen una copia superficial.
El siguiente ejemplo ilustra este punto:
~/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules$ cat -n dupclone1.rb 1 class Point 2 attr_accessor :coords 3 def initialize(* coords) 4 @coords = coords 5 end 6 end 7 8 if __FILE__ == $0 9 puts "dup" 10 p = Point.new(1, 2, 3) 11 q = p.dup 12 puts p.inspect 13 puts q.inspect 14 15 q.coords[1] = 4 16 puts p.inspect 17 puts q.inspect 18 19 puts "clone" 20 p = Point.new(1, 2, 3) 21 q = p.clone 22 puts p.inspect 23 puts q.inspect 24 25 q.coords[1] = 4 26 puts p.inspect 27 puts q.inspect 28 endLa ejecución nos muestra que la copia es superficial:
~/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules$ ruby dupclone1.rb dup #<Point:0x100169008 @coords=[1, 2, 3]> #<Point:0x100168fe0 @coords=[1, 2, 3]> #<Point:0x100169008 @coords=[1, 4, 3]> #<Point:0x100168fe0 @coords=[1, 4, 3]> clone #<Point:0x100168c20 @coords=[1, 2, 3]> #<Point:0x100168bf8 @coords=[1, 2, 3]> #<Point:0x100168c20 @coords=[1, 4, 3]> #<Point:0x100168bf8 @coords=[1, 4, 3]>Lo que se necesita es una copia profunda.
initialize_copy
,
los métodos clone
y dup
lo invocarán en el objeto copia.
Al método initialize_copy
se le pasa el objeto original como argumento.
El valor retornado por initialize_copy
es ignorado:
~/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules$ cat -n dupclone2.rb 1 class Point 2 attr_accessor :coords 3 def initialize(* coords) 4 @coords = coords 5 end 6 7 def initialize_copy(orig) 8 @coords = orig.coords.dup 9 # or better 10 # @coords = @coords.dup 11 end 12 end 13 14 if __FILE__ == $0 15 puts "dup" 16 p = Point.new(1, 2, 3) 17 q = p.dup 18 puts p.inspect 19 puts "q = p.dup = "+q.inspect 20 21 q.coords[1] = 4 22 puts "Changed q[1] to 4 and p has "+p.inspect 23 puts "Changed q[1] to 4 and q has "+q.inspect 24 25 puts "clone" 26 p = Point.new(1, 2, 3) 27 q = p.clone 28 puts p.inspect 29 puts "q = p.clone = "+q.inspect 30 31 q.coords[1] = 4 32 puts "Changed q[1] to 4 and p has "+p.inspect 33 puts "Changed q[1] to 4 and q has "+q.inspect 34 endLa ejecución produce la siguiente salida:
~/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules$ ruby dupclone2.rb dup #<Point:0x100168900 @coords=[1, 2, 3]> q = p.dup = #<Point:0x1001688d8 @coords=[1, 2, 3]> Changed q[1] to 4 and p has #<Point:0x100168900 @coords=[1, 2, 3]> Changed q[1] to 4 and q has #<Point:0x1001688d8 @coords=[1, 4, 3]> clone #<Point:0x1001683d8 @coords=[1, 2, 3]> q = p.clone = #<Point:0x1001683b0 @coords=[1, 2, 3]> Changed q[1] to 4 and p has #<Point:0x1001683d8 @coords=[1, 2, 3]> Changed q[1] to 4 and q has #<Point:0x1001683b0 @coords=[1, 4, 3]>
Casiano Rodriguez León 2015-01-07