460 votes

Quelle est la différence entre comprendre et s’étendent en Ruby ?

Juste obtenir ma tête autour de Ruby métaprogrammation... les modules/mixin parviennent toujours à me confondre.

  • inclure : mélanges en méthodes module spécifié en tant que méthodes d’instance dans la classe cible
  • étendre : mélanges en méthodes module spécifié en tant que méthodes de la classe dans la classe cible

Est donc la principale différence vient cela ou est un plus grand dragon TAPI ? par exemple

369voto

John Douthat Points 28189

étendre - ajoute le module spécifié est des méthodes et des constantes de la cible métaclasse (c'est à dire la classe singleton) par exemple

  • si vous appelez Klazz.extend(Mod), maintenant Klazz a du Mod méthodes (comme les méthodes de la classe)
  • si vous appelez obj.extend(Mod), maintenant obj a du Mod méthodes (comme les méthodes d'instance), mais aucune autre instance de la de la obj.class a ces méthodes.
  • extend est une méthode publique

inclure Par défaut, il se mélange dans le module spécifié méthodes comme les méthodes d'instance dans la cible du module de classe. par exemple

  • si vous appelez class Klazz; include Mod; end;, maintenant toutes les instances de Klazz avoir accès à du Mod méthodes (comme les méthodes d'instance)
  • include est une méthode privée, car il est destiné à être appelé à partir de la classe de conteneur/module.

Cependant, des modules très souvent remplacer include's par le comportement de singe de correction de l' included méthode. Ceci est très important dans l'héritage des Rails de code. plus de détails à partir de Yehuda Katz.

Plus de détails sur l' include, avec son comportement par défaut, en supposant que vous avez exécutez le code suivant

class Klazz
  include Mod
end
  • Si le Mod est déjà inclus dans Klazz, ou l'un de ses ancêtres, la déclaration n'a pas d'effet
  • Il comprend aussi des Mod les constantes de Klazz, tant qu'ils ne sont pas en conflit
  • Il donne Klazz accès à du Mod variables de module, par exemple, @@foo ou @@bar
  • soulève ArgumentError si il y a cyclique comprend
  • Attache du module, en l'appelant de l'ancêtre immédiat (c'est à dire Il ajoute Mod pour Klazz.ancêtres, mais le Mod n'est pas ajouté à la chaîne de Klazz.super-classe.super-classe.super-classe. Ainsi, l'appel de super dans Klazz#foo va vérifier pour les Mod#foo avant de vérifier à Klazz réel de la super-classe de la méthode foo. Voir la RubySpec pour les détails).

Bien sûr, le rubis de la documentation de base est toujours le meilleur endroit où aller pour ces choses. Le RubySpec projet est également une ressource fantastique, parce qu'ils documenter les fonctionnalités précisément.

273voto

domgblackwell Points 2333

Ce que vous avez dit est correct. Cependant, il ya plus à lui que cela.

Si vous avez une classe Klazz et le module Mod, y compris l' Mod en Klazz donne des instances de Klazz d'accès à des objets d' Mod's méthodes. Ou vous pouvez étendre Klazz avec Mod donnant la classe Klazz accès Mod's méthodes. Mais aussi, vous pouvez étendre un objet arbitraire avec o.extend Mod. Dans ce cas, la personne objet s' Mod's méthodes, même si tous les autres objets de la même classe que l' o ne le font pas.

17voto

Toby Hede Points 22128

C’est exact.

Dans les coulisses, inclure est en fait un alias pour append_features, qui (à partir de la documentation) :

Implémentation de Ruby par défaut consiste à ajouter les constantes, les méthodes et variables de module de ce module à aModule si ce module n’a pas déjà été ajouté au aModule ou l’un de ses ancêtres.

3voto

Ho-Sheng Hsiao Points 459

Toutes les autres réponses sont bonnes, y compris la pointe de creuser à travers RubySpecs:

https://github.com/rubyspec/rubyspec/blob/master/core/module/include_spec.rb

https://github.com/rubyspec/rubyspec/blob/master/core/module/extend_object_spec.rb

Comme pour les cas d'utilisation:

Si vous comprennent module ReusableModule dans la classe ClassThatIncludes, les méthodes, les constantes, les classes, les submodules, et d'autres déclarations obtient référencés.

Si vous étendez la classe ClassThatExtends avec le module ReusableModule, les méthodes et les constantes obtient copié. Évidemment, si vous n'êtes pas prudent, vous pouvez perdre beaucoup de mémoire dynamique de la duplication des définitions.

Si vous utilisez ActiveSupport::Inquiétude, l' .inclus() fonctionnalité vous permet de réécrire l', y compris la classe directement. module ClassMethods à l'intérieur d'une Préoccupation obtient étendu (copié) dans l', y compris la classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X