8
votes

Quelles classes de rubis appuient .clone?

Ruby définit #clone dans objet . À ma surprise, certaines classes soulèvent des exceptions lors de l'appelant. J'ai trouvé nilclass , Trueclass , Falseclass , fixnum ayant ce comportement.

1) est une liste complète des classes (au moins des classes de base), qui n'autorisent pas #clone ? Ou existe-t-il un moyen de détecter si une classe spécifique prend en charge #clone ?

2) Quel est le problème avec 42.Clone ?


1 commentaires

Je veux vraiment savoir comment vous testez si une classe est clonable moi-même. Il semble que si une classe ne veuille pas se laisser clonée, il devrait faire de la méthode de clone privée qu'il hérite de l'objet afin que vous puissiez tester son existence uniquement sous Public_methods. Semble être bon sens pour moi.


6 Réponses :


0
votes

Vous ne pouvez pas cloner des classes immuables. C'est à dire. Vous ne pouvez avoir qu'une seule instance d'objet 42 (en tant que fixnum), mais peut avoir de nombreuses instances de "42" (car la chaîne est mutable). Vous ne pouvez pas cloner des symboles aussi bien qu'ils sont quelque chose comme des chaînes immuables.

Vous pouvez vérifier cela dans IRB avec méthode Object_ID. (symboles et fixnums vous donneront le même objet_id après des appels répétitifs)


2 commentaires

L'utabilité n'a rien à voir avec elle (en fait, vous pouvez ajouter un état à un correctif).


Comportement par défaut vraiment bizarre pour Fixnum, en particulier étant donné qu'il a la méthode du clone, D.Class.Method_Definefin? (: Clone) == true



7
votes

Je ne pense pas qu'il existe une liste formelle, au moins à moins que vous ne comptez en lecture de la source. La raison 2) ne fonctionne pas est à cause d'une optimisation appliquée aux fixations. Ils sont stockés / passés à l'intérieur de leurs valeurs réelles (ainsi sont vraies, fausses et nil) et non comme des pointeurs. La solution naïve consiste à avoir juste 42.cLone renvoyer le même 42 , mais ensuite le invariant obj.clone.object_id! = Obj.object_id ne serait plus détenir, 42.Clone ne serait pas en train de cloner.


1 commentaires

obj.clone.object_id! = obj.object_id être true et obj.clone.object_id == obj.object_id pas toujours vrai sont différents sont différents. Que l'ancien ne veut pas dire ne signifie pas que ce dernier ne le fait pas.



5
votes

fixnum est une classe spéciale donnée un traitement spécial par la langue. À partir du moment où votre programme lance, il existe exactement un correctif pour chaque nombre que la classe peut représenter, et ils ont une représentation spéciale qui ne prend aucun espace supplémentaire - de cette façon, les opérations de base des mathématiques ne sont pas allouées et négociantes mémoire comme un fou. Pour cette raison, il ne peut y avoir plus d'un 42.

Pour les autres, ils ont tous une chose en commun: ce sont des singletons. Il n'y a qu'une seule instance d'une classe Singleton par définition, tellement essayant de cloner c'est une erreur.


1 commentaires

"Pour cette raison, il ne peut y avoir plus d'un 42.". Et pourquoi serait-il besoin d'être? C'est parfait.



1
votes

Je ne sais toujours pas comment tester la clonabilité correctement, mais voici une façon très maladroite et diabolique de tester la clonablity à l'aide de la piégeage des erreurs: xxx pré>

et voici comment vous pouvez cloner même le Non désagréable. Au moins pour les très rares classes que je l'ai fatiguée. P> xxx pré>

Voici quelques tests d'échantillon: P>

b = :b
puts "clonable? #{clonable? b}"

b = proc { b == "b" }
puts "clonable? #{clonable? b}"

b = [:a, :b, :c]
c = super_mega_clone(b)

puts "c: #{c.object_id}"
puts "b: #{b.object_id}"
puts "b == c => #{b == c}"
b.each_with_index do |value, index|
  puts "[#{index}] b: #{b[index].object_id} c: #{c[index].object_id}"
end
b[0] = :z

puts "b == c => #{b == c}"
b.each_with_index do |value, index|
  puts "[#{index}] b: #{b[index].object_id} c: #{c[index].object_id}"
end

b = :a
c = super_mega_clone(b)
puts "b: #{b.object_id} c: #{c.object_id}"

> clonable? false
> clonable? true
> c: 2153757040
> b: 2153757480
> b == c => true
> [0] b: 255528 c: 255528
> [1] b: 255688 c: 255688
> [2] b: 374568 c: 374568
> b == c => false
> [0] b: 1023528 c: 255528
> [1] b: 255688 c: 255688
> [2] b: 374568 c: 374568
> b: 255528 c: 255528


0 commentaires

1
votes

J'ai fait un git grep "ne peut pas cloner" du code source de yarv et obtenu xxx

Les première et troisième lignes indiquent que vous ne pouvez pas cloner Un singleton.

La deuxième ligne fait référence à rb_special_const_p (obj) . Mais cela va au-delà de mon ken.


0 commentaires

0
votes

rails semble étendre les classes que vous mentionnez avec une méthode "duplicable? ()".

http://api.rubyonRails.org/ Fichiers / ActiveSupport / lib / actif_support / core_ext / objet / duplicable_rb.html


1 commentaires

Duplicable? () Est également défini dans le gemme ActiveSupport