Question

Existe-t-il un moyen simple de tester si un objet est immuable (nombres, nil) ou non (Array, Hash, objets)? En d’autres termes, pourrait-il être modifié par les effets secondaires d’un autre code?

Motivation: je souhaite créer un magasin de valeurs versionné, mais certaines données sont des tableaux. Certains tableaux vont stocker des objets personnalisés, et je pourrais inverser la relation en stockant la propriété "in" et en la recherchant. Mais j'aimerais aussi pouvoir stocker des tableaux de symboles, d'autres tableaux, etc.

Était-ce utile?

La solution

Il n'y a pas d'objets primitifs dans Ruby. Cela ne peut donc pas être détecté de manière simple.

Ne pouvez-vous pas simplement utiliser Marshal ou YAML pour votre magasin avec version? Ensuite, vous recevrez gratuitement le chargement et l'enregistrement de tous les types d'objet. Pourquoi réinventer la roue?

Je ne sais pas ce que vous voulez réaliser exactement, mais il serait peut-être intéressant de regarder la source de YAML de voir comment ils gèrent ce problème. L'implémentation d'encodage Ruby YAML implémente simplement la méthode to_yaml pour toutes les classes pertinentes. Voir yaml .

Autres conseils

J'ai trouvé un moyen inefficace:

class Object
  def primitive?
    begin
      self.dup
      false
    rescue TypeError
      true
    end
  end
end

L’idée de mutabilité ne s’applique pas vraiment en Ruby de la même manière qu’en d’autres langues. Le seul objet immuable est un objet gelé. Vous pouvez même ajouter des méthodes et des variables d'instance à Fixnums. Par exemple:

class Fixnum
  attr_accessor :name
end
1.name = "one"
2.name = "two"

Évidemment, la grande majorité du temps, les gens ne seront pas assez pathologiques pour ajouter des attributs à Fixnum, mais le fait est qu'aucun objet non gelé n'est vraiment immuable.

Si vous pouvez créer une liste canonique de classes que vous voulez supposer immuables, vous pouvez simplement les parcourir et leur donner à toutes une méthode immuable? () qui renvoie true (et une version qui retourne false). Mais comme l’a dit wvanbergen, le meilleur moyen de s’assurer que votre copie d’un objet ne change pas est de le copier en profondeur avec Marshal.

Autre différence: les objets nativement immuables ne peuvent pas être gelés, mais ils renvoient toujours faux après avoir été gelés?

5.freeze.frozen? == false

Freeze ne déclenche pas d'exception (contrairement à dup). Cependant, il modifie (de manière permanente!) les objets mutables.

J'ai constaté que je pouvais (du moins dans son état actuel) organiser mon application pour qu'elle fonctionne avec des objets gelés. Ruby me donnera une exception si j'essaie de les modifier directement. Toutefois, le gel n’affecte que le premier niveau de l’objet , et les tableaux, etc., qui y sont stockés peuvent toujours être modifiés.

Ceci s’applique uniquement à 1.8 - 5.frozen? renvoie true dans ruby1.9 (mais pas dans irb1.9)

scroll top