Qu’est-ce que attr_accessor dans Ruby?

J’ai du mal à comprendre attr_accessor dans Ruby. Quelqu’un peut m’expliquer cela?

Disons que vous avez une Person classe.

 class Person end person = Person.new person.name # => no method error 

De toute évidence, nous n’avons jamais défini le name méthode. Faisons cela.

 class Person def name @name # simply returning an instance variable @name end end person = Person.new person.name # => nil person.name = "Dennis" # => no method error 

Aha, nous pouvons lire le nom, mais cela ne signifie pas que nous pouvons atsortingbuer le nom. Ce sont deux méthodes différentes. Le premier est appelé lecteur et le dernier est appelé écrivain . Nous n’avons pas encore créé l’écrivain alors faisons-le.

 class Person def name @name end def name=(str) @name = str end end person = Person.new person.name = 'Dennis' person.name # => "Dennis" 

Impressionnant. Maintenant, nous pouvons écrire et lire la variable d’instance @name utilisant des méthodes de lecture et d’écriture. Sauf que cela se fait si souvent, pourquoi perdre du temps à écrire ces méthodes à chaque fois? Nous pouvons le faire plus facilement.

 class Person attr_reader :name attr_writer :name end 

Même cela peut devenir répétitif. Lorsque vous voulez à la fois lecteur et écrivain utilisez simplement accessor!

 class Person attr_accessor :name end person = Person.new person.name = "Dennis" person.name # => "Dennis" 

Fonctionne de la même manière! Et devinez quoi: la variable d’instance @name dans notre object person sera définie comme lorsque nous l’avons fait manuellement, vous pouvez donc l’utiliser dans d’autres méthodes.

 class Person attr_accessor :name def greeting "Hello #{@name}" end end person = Person.new person.name = "Dennis" person.greeting # => "Hello Dennis" 

C’est tout. Pour comprendre comment les attr_reader , attr_writer et attr_accessor génèrent des méthodes pour vous, lisez d’autres réponses, des livres, des ruby ​​docs.

attr_accessor est juste une méthode . (Le lien devrait fournir plus d’informations sur son fonctionnement – examinez les paires de méthodes générées et un didacticiel devrait vous montrer comment l’utiliser).

L’astuce est que la class n’est pas une définition dans Ruby (c’est “juste une définition” dans des langages comme C ++ et Java), mais c’est une expression qui évalue . C’est au cours de cette évaluation que la méthode attr_accessor est appelée, ce qui modifie à son tour la classe actuelle – rappelez-vous le récepteur implicite: self.attr_accessor , où self est l’object de classe “open” à ce stade.

Le besoin pour attr_accessor et ses amis, c’est bien:

  1. Ruby, comme Smalltalk, n’autorise pas l’access aux variables d’instance en dehors des méthodes 1 pour cet object. En d’autres termes, les variables d’instance ne sont pas accessibles sous la forme xy , comme cela est courant dans Java, ou même Python. En Ruby y est toujours pris comme un message à envoyer (ou “méthode d’appeler”). Ainsi, les méthodes attr_* créent des wrappers qui proxy l’access à l’instance @variable via des méthodes créées dynamicment.

  2. Chaudière

J’espère que cela clarifie certains des petits détails. Heureux codage


1 Ce n’est pas ssortingctement vrai et il y a quelques “techniques” à ce sujet , mais il n’y a pas de support de syntaxe pour l’access “variable d’instance publique”.

attr_accessor est (comme @pst indiqué) juste une méthode. Qu’est-ce qu’il fait est de créer plus de méthodes pour vous.

Donc, ce code ici:

 class Foo attr_accessor :bar end 

est équivalent à ce code:

 class Foo def bar @bar end def bar=( new_value ) @bar = new_value end end 

Vous pouvez écrire ce type de méthode vous-même en Ruby:

 class Module def var( method_name ) inst_variable_name = "@#{method_name}".to_sym define_method method_name do instance_variable_get inst_variable_name end define_method "#{method_name}=" do |new_value| instance_variable_set inst_variable_name, new_value end end end class Foo var :bar end f = Foo.new p f.bar #=> nil f.bar = 42 p f.bar #=> 42 

attr_accessor est très simple:

 attr_accessor :foo 

est un raccourci pour:

 def foo=(val) @foo = val end def foo @foo end 

ce n’est rien de plus qu’un getter / setter pour un object

C’est juste une méthode qui définit les méthodes getter et setter pour les variables d’instance. Un exemple de mise en œuvre serait:

 def self.attr_accessor(*names) names.each do |name| define_method(name) {instance_variable_get("@#{name}")} # This is the getter define_method("#{name}=") {|arg| instance_variable_set("@#{name}", arg)} # This is the setter end end 

Fondamentalement, ils falsifient des atsortingbuts de données accessibles au public, ce que Ruby n’a pas.

J’ai également fait face à ce problème et j’ai écrit une réponse assez longue à cette question. Il y a déjà d’excellentes réponses à cette question, mais j’espère que ma réponse peut aider

Initialiser la méthode

Initialize vous permet de définir des données sur une instance d’object lors de la création de l’instance plutôt que de devoir les définir sur une ligne distincte dans votre code chaque fois que vous créez une nouvelle instance de la classe.

 class Person attr_accessor :name def initialize(name) @name = name end def greeting "Hello #{@name}" end end person = Person.new("Denis") puts person.greeting 

Dans le code ci-dessus, nous définissons le nom «Denis» en utilisant la méthode initialize en transmettant Dennis via le paramètre dans Initialize. Si nous voulions définir le nom sans la méthode d’initialisation, nous pourrions le faire comme ceci:

 class Person attr_accessor :name # def initialize(name) # @name = name # end def greeting "Hello #{name}" end end person = Person.new person.name = "Dennis" puts person.greeting 

Dans le code ci-dessus, nous définissons le nom en appelant la méthode de réglage attr_accessor à l’aide de person.name, plutôt que de définir les valeurs lors de l’initialisation de l’object.

Les deux «méthodes» de ce travail fonctionnent, mais l’initialisation nous permet d’économiser du temps et des lignes de code.

C’est le seul travail d’initialisation. Vous ne pouvez pas appeler lors de l’initialisation en tant que méthode. Pour obtenir réellement les valeurs d’un object instance, vous devez utiliser des getters et des setters (attr_reader (get), attr_writer (set) et attr_accessor (les deux)). Voir ci-dessous pour plus de détails sur ceux-ci.

Getters, Setters (attr_reader, attr_writer, attr_accessor)

Getters, attr_reader: le but d’un getter est de renvoyer la valeur d’une variable d’instance particulière. Consultez l’exemple de code ci-dessous pour obtenir une ventilation à ce sujet.

 class Item def initialize(item_name, quantity) @item_name = item_name @quantity = quantity end def item_name @item_name end def quantity @quantity end end example = Item.new("TV",2) puts example.item_name puts example.quantity 

Dans le code ci-dessus, vous appelez les méthodes “item_name” et “quantity” sur l’instance de Item “example”. Les options «mettre example.item_name» et «example.quantity» renverront (ou «récupéreront») la valeur des parameters passés dans «l’exemple» et les afficheront à l’écran.

Heureusement, dans Ruby, il existe une méthode inhérente qui nous permet d’écrire ce code plus succinctement. la méthode attr_reader. Voir le code ci-dessous;

 class Item attr_reader :item_name, :quantity def initialize(item_name, quantity) @item_name = item_name @quantity = quantity end end item = Item.new("TV",2) puts item.item_name puts item.quantity 

Cette syntaxe fonctionne exactement de la même manière, mais elle nous évite six lignes de code. Imaginez si vous aviez 5 autres états atsortingbuables à la classe Item? Le code serait long rapidement.

Setters, attr_writer: Ce qui m’a tout d’abord frappé avec les méthodes de setter, c’est qu’à mes yeux, il semblait avoir une fonction identique à la méthode d’initialisation. Ci-dessous, j’explique la différence en fonction de ma compréhension;

Comme indiqué précédemment, la méthode initialize vous permet de définir les valeurs d’une instance d’un object lors de la création de l’object.

Mais que faire si vous souhaitiez définir les valeurs ultérieurement, après la création de l’instance, ou les modifier après leur initialisation? Ce serait un scénario où vous utiliseriez une méthode de réglage. C’EST LA DIFFÉRENCE. Vous n’avez pas besoin de “définir” un état particulier lorsque vous utilisez la méthode attr_writer initialement.

Le code ci-dessous est un exemple d’utilisation d’une méthode de définition pour déclarer la valeur nom_article pour cette instance de la classe Item. Notez que nous continuons à utiliser la méthode getter attr_reader pour que nous puissions obtenir les valeurs et les imprimer à l’écran, au cas où vous voudriez tester le code vous-même.

 class Item attr_reader :item_name def item_name=(str) @item_name = (str) end end 

Le code ci-dessous est un exemple d’utilisation de attr_writer pour raccourcir à nouveau notre code et gagner du temps.

 class Item attr_reader :item_name attr_writer :item_name end item = Item.new puts item.item_name = "TV" 

Le code ci-dessous est une réitération de l’exemple d’initialisation ci-dessus, où nous utilisons initialize pour définir la valeur des objects de item_name lors de la création.

 class Item attr_reader :item_name def initialize(item_name) @item_name = item_name end end item = Item.new("TV") puts item.item_name 

attr_accessor: Exécute les fonctions à la fois de attr_reader et d’attr_writer, vous permettant d’économiser une ligne de code supplémentaire.

Je pense qu’une partie de ce qui confond les nouveaux Rubyistes / programmeurs (comme moi) est:

“Pourquoi ne puis-je pas simplement dire à l’instance qu’elle a un atsortingbut donné (par exemple, name) et lui donner une valeur tout en un?”

Un peu plus généralisé, mais voici comment il a cliqué pour moi:

Donné:

 class Person end 

Nous n’avons pas défini Personne comme quelque chose pouvant avoir un nom ou tout autre atsortingbut.

Donc, si nous avons alors:

 baby = Person.new 

… et essayez de leur donner un nom …

 baby.name = "Ruth" 

Nous obtenons une erreur car, dans Rubyland, une classe d’object Personne n’est pas associée à ou capable d’avoir un “nom” … pour le moment!

MAIS nous pouvons utiliser n’importe quelle méthode donnée (voir les réponses précédentes) pour dire: “Une instance d’une classe Person ( baby ) peut maintenant avoir un atsortingbut appelé” name “, nous avons donc non seulement une méthode syntaxique pour obtenir et mettre ce nom, mais il est logique pour nous de le faire. ”

Encore une fois, bash cette question sous un angle légèrement différent et plus général, mais j’espère que cela aidera la prochaine instance de classe Personne qui trouvera son chemin vers ce sujet.

Si vous êtes familier avec le concept de POO, vous devez vous familiariser avec la méthode getter et setter. attr_accessor fait de même avec Ruby.

Getter et Setter de manière générale

 class Person def name @name end def name=(str) @name = str end end person = Person.new person.name = 'Eshaan' person.name # => "Eshaan" 

Méthode Setter

 def name=(val) @name = val end 

Méthode Getter

 def name @name end 

Méthode Getter et Setter en Ruby

 class Person attr_accessor :name end person = Person.new person.name = "Eshaan" person.name # => "Eshaan" 

La plupart des réponses ci-dessus utilisent le code. Cette explication tente de répondre sans utiliser de code:

Explication par analogie

Les parties extérieures ne peuvent pas accéder aux secrets internes de la CIA

  • Imaginons un endroit vraiment secret: la CIA. Personne ne sait ce qui se passe dans la CIA, à part les personnes à l’intérieur de la CIA. En d’autres termes, les personnes externes ne peuvent accéder à aucune information dans la CIA. Mais comme il n’est pas bon d’avoir une organisation complètement secrète, certaines informations sont mises à la disposition du monde extérieur – seulement des choses que la CIA veut que tout le monde connaisse bien sûr: par exemple, le directeur de la CIA à tous les autres ministères, etc. Autres informations: par exemple, qui sont ses agents secrets en Irak ou en Afghanistan? Ce genre de choses restra probablement un secret pour les 150 prochaines années.

  • Si vous êtes en dehors de la CIA, vous ne pouvez accéder qu’aux informations mises à la disposition du public. Ou pour utiliser le langage CIA, vous pouvez uniquement accéder aux informations qui sont “effacées”.

  • Les informations que la CIA veut mettre à la disposition du grand public en dehors de la CIA s’appellent: atsortingbuts.

La signification des atsortingbuts read et write:

  • Dans le cas de la CIA, la plupart des atsortingbuts sont en lecture seule. Cela signifie que si vous êtes une partie externe à la CIA, vous pouvez demander: “Qui est le directeur de la CIA?” et vous aurez une réponse directe. Mais ce que vous ne pouvez pas faire avec les atsortingbuts “en lecture seule” est de faire des changements dans la CIA. Par exemple, vous ne pouvez pas passer un coup de fil et décidez soudainement que vous voulez que Kim Kardashian soit le directeur ou que vous souhaitiez que Paris Hilton soit le commandant en chef.

  • Si les atsortingbuts vous donnaient un access “en écriture”, vous pouviez alors apporter des modifications, même si vous étiez à l’extérieur. Sinon, la seule chose que vous pouvez faire est de lire.

    En d’autres termes, les accesseurs vous permettent d’effectuer des recherches ou d’apporter des modifications à des organisations qui ne laissent pas entrer des personnes externes, selon que les accesseurs sont en lecture ou en écriture.

Les objects à l’intérieur d’une classe peuvent facilement accéder les uns aux autres

  • Par contre, si vous étiez déjà à l’ intérieur de la CIA, vous pourriez facilement appeler votre agent de la CIA à Kaboul et lui demander s’il souhaite prendre une bière avec l’informateur local de Kaboul après le travail. Mais si vous êtes en dehors de la CIA, vous ne pourrez tout simplement pas y accéder: vous ne pourrez pas savoir qui ils sont (access en lecture) et vous ne pourrez pas modifier leur mission (access en écriture).

Exactement la même chose avec les classes et votre capacité à accéder à des variables, propriétés et méthodes en leur sein. HTH! Des questions, s’il vous plaît demander et j’espère que je peux clarifier.

Simplement, cela définira un setter et un getter pour la classe.

Notez que

 attr_reader :v is equivalant to def v @v end attr_writer :v is equivalant to def v=(value) @v=value end 

Alors

 attr_accessor :v which means attr_reader :v; attr_writer :v 

sont équivalents pour définir un setter et un getter pour la classe.

Simplement attr-accessor crée les getter et setter pour les atsortingbuts spécifiés

Une autre façon de le comprendre consiste à déterminer quel code d’erreur il élimine en attr_accessor .

Exemple:

 class BankAccount def initialize( account_owner ) @owner = account_owner @balance = 0 end def deposit( amount ) @balance = @balance + amount end def withdraw( amount ) @balance = @balance - amount end end 

Les méthodes suivantes sont disponibles:

 $ bankie = BankAccout.new("Iggy") $ bankie $ bankie.deposit(100) $ bankie.withdraw(5) 

Les méthodes suivantes génèrent une erreur:

 $ bankie.owner #undefined method `owner'... $ bankie.balance #undefined method `balance'... 

owner et l’ balance ne sont pas, techniquement, une méthode , mais un atsortingbut. La classe BankAccount n’a pas de def owner def balance ni de def balance . Si c’est le cas, vous pouvez utiliser les deux commandes ci-dessous. Mais ces deux méthodes ne sont pas là. Cependant, vous pouvez accéder aux atsortingbuts comme si vous attr_accessor une méthode via attr_accessor !! D’où le mot attr_accessor . Atsortingbut. Accesseur. Il accède à des atsortingbuts comme vous accéderiez à une méthode.

Ajouter attr_accessor :balance, :owner vous permet de lire et d’écrire balance “méthodes” de balance et de owner . Vous pouvez maintenant utiliser les deux dernières méthodes.

 $ bankie.balance $ bankie.owner 

Définit un atsortingbut nommé pour ce module, où le nom est symbol.id2name, créant une variable d’instance (@name) et une méthode d’access correspondante pour le lire. Crée également une méthode appelée name = pour définir l’atsortingbut.

 module Mod attr_accessor(:one, :two) end Mod.instance_methods.sort #=> [:one, :one=, :two, :two=] 

Pour résumer un atsortingbut atsortingbut aka attr_accessor vous donne deux méthodes gratuites.

Comme à Java, on les appelle des getters et des setters.

Beaucoup de réponses ont montré de bons exemples, alors je vais être bref.

#le_atsortingbut

et

# the_atsortingbute =

Dans l’ancien ruby ​​docs, une balise hash # signifie une méthode. Il pourrait également inclure un préfixe de nom de classe … MyClass # my_method

Atsortingbuts et méthodes d’access

Les atsortingbuts sont des composants de classe accessibles depuis l’extérieur de l’object. Ils sont appelés propriétés dans de nombreux autres langages de programmation. Leurs valeurs sont accessibles en utilisant la “notation par points”, comme dans object_name.atsortingbute_name. Contrairement à Python et à quelques autres langages, Ruby ne permet pas d’accéder directement aux variables d’instance depuis l’extérieur de l’object.

 class Car def initialize @wheels = 4 # This is an instance variable end end c = Car.new c.wheels # Output: NoMethodError: undefined method `wheels' for # 

Dans l’exemple ci-dessus, c est une instance (object) de la classe Car. Nous avons tenté sans succès de lire la valeur de la variable d’instance wheels en dehors de l’object. Ce qui s’est passé, c’est que Ruby a tenté d’appeler une méthode nommée wheels dans l’object c, mais aucune méthode de ce type n’a été définie. En bref, object_name.atsortingbute_name tente d’appeler une méthode nommée atsortingbute_name dans l’object. Pour accéder à la valeur de la variable roues depuis l’extérieur, nous devons implémenter une méthode d’instance de ce nom, qui renverra la valeur de cette variable lorsqu’elle sera appelée. C’est ce qu’on appelle une méthode d’access. Dans le contexte général de la programmation, la manière habituelle d’accéder à une variable d’instance depuis l’extérieur de l’object consiste à implémenter des méthodes d’accesseur, également appelées méthodes getter et setter. Un getter permet de lire la valeur d’une variable définie dans une classe depuis l’extérieur et un setter permet de l’écrire de l’extérieur.

Dans l’exemple suivant, nous avons ajouté des méthodes getter et setter à la classe Car pour accéder à la variable wheels depuis l’extérieur de l’object. Ce n’est pas la “manière Ruby” de définir les getters et les setters; il sert uniquement à illustrer ce que font les méthodes getter et setter.

 class Car def wheels # getter method @wheels end def wheels=(val) # setter method @wheels = val end end f = Car.new f.wheels = 4 # The setter method was invoked f.wheels # The getter method was invoked # Output: => 4 

L’exemple ci-dessus fonctionne et un code similaire est couramment utilisé pour créer des méthodes de lecture et de définition dans d’autres langages. Cependant, Ruby fournit un moyen plus simple de le faire: trois méthodes intégrées appelées attr_reader, attr_writer et attr_acessor. La méthode attr_reader rend une variable d’instance lisible de l’extérieur, attr_writer le rend accessible en écriture et attr_acessor le rend lisible et accessible en écriture.

L’exemple ci-dessus peut être réécrit comme ceci.

 class Car attr_accessor :wheels end f = Car.new f.wheels = 4 f.wheels # Output: => 4 

Dans l’exemple ci-dessus, l’atsortingbut roues sera lisible et accessible en écriture depuis l’extérieur de l’object. Si au lieu de attr_accessor, nous avons utilisé attr_reader, il serait en lecture seule. Si nous utilisions attr_writer, ce serait en écriture seule. Ces trois méthodes ne sont pas getters et setters en elles-mêmes mais, lorsqu’elles sont appelées, elles créent des méthodes de getter et de setter pour nous. Ce sont des méthodes qui génèrent dynamicment (par programmation) d’autres méthodes; c’est ce qu’on appelle la métaprogrammation.

Le premier exemple (plus long), qui n’utilise pas les méthodes intégrées de Ruby, ne doit être utilisé que lorsqu’un code supplémentaire est requirejs dans les méthodes getter et setter. Par exemple, une méthode de réglage peut avoir besoin de valider des données ou de faire des calculs avant d’affecter une valeur à une variable d’instance.

Il est possible d’accéder à (lire et écrire) des variables d’instance en dehors de l’object, en utilisant les méthodes intégrées instance_variable_get et instance_variable_set. Cependant, cela est rarement justifiable et généralement une mauvaise idée, car le contournement de l’encapsulation a tendance à causer toutes sortes de dégâts.

Hmmm. Beaucoup de bonnes réponses. Voici mes quelques centimes dessus.

  • attr_accessor est une méthode simple qui nous aide à nettoyer ( DRY ) les méthodes getter and setter répétitives .

  • Pour que nous puissions nous concentrer davantage sur l’écriture de la logique d’affaires et ne pas nous soucier des créateurs et des acquéreurs.

La fonctionnalité principale de attr_accessor par rapport aux autres est la possibilité d’accéder aux données à partir d’autres fichiers.
Donc, vous avez généralement attr_reader ou attr_writer, mais la bonne nouvelle est que Ruby vous permet de combiner ces deux éléments avec attr_accessor. J’y pense comme ma méthode à suivre, car il est plus rond ou polyvalent. En outre, gardez à l’esprit que dans Rails, ceci est éliminé car il le fait pour vous dans le back end. En d’autres termes, il vaut mieux utiliser attr_acessor que les deux autres car vous n’avez pas à vous soucier d’être spécifique, l’accesseur couvre tout. Je sais que c’est plus une explication générale mais cela m’a aidé en tant que débutant.

J’espère que cela a aidé!