J'ai du mal à comprendre attr_accessor
en Ruby .
Quelqu'un peut m'expliquer cela?
git
n'a rien à voir avec attr_accessor
. Git est un logiciel de contrôle de version, alors qu'il attr_accessor
s'agit d'une méthode dans Ruby .
J'ai du mal à comprendre attr_accessor
en Ruby .
Quelqu'un peut m'expliquer cela?
git
n'a rien à voir avec attr_accessor
. Git est un logiciel de contrôle de version, alors qu'il attr_accessor
s'agit d'une méthode dans Ruby .
Réponses:
Disons que vous avez une classe Person
.
class Person
end
person = Person.new
person.name # => no method error
Évidemment, nous n'avons jamais défini de méthode name
. 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 attribuer le nom. Ce sont deux méthodes différentes. Le premier est appelé lecteur et le second est appelé écrivain . Nous n'avons pas encore créé l'auteur 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
aide 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 l'accesseur!
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 objet personne 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 ça. Afin de comprendre comment attr_reader
, attr_writer
et les attr_accessor
méthodes génèrent réellement des méthodes pour vous, lisez d'autres réponses, livres, ruby docs.
attr_accessor
s'agit d'une méthode appelée sur la classe actuelle et d' :name
un paramètre que vous transmettez à cette méthode. Ce n'est pas une syntaxe spéciale, c'est un simple appel de méthode. Si vous deviez lui donner une @name
variable, cela n'aurait aucun sens, car @name contiendrait nil
. Ce serait donc comme écrire attr_accessor nil
. Vous ne lui passez pas une variable dont il a besoin pour créer, vous passez le nom que vous voulez que la variable soit appelée.
name
et variable @name
ne sont pas la même chose. Ne les confondez pas. Vous avez une variable d'instance @name
dans votre classe, et vous définissez attr_reader :name
pour pouvoir la lire de l'extérieur. Sans, attr_reader
il n'y a aucun moyen simple d'accéder à l' @name
extérieur de votre classe.
attr_accessor n'est qu'une méthode . (Le lien devrait fournir plus d'informations sur son fonctionnement - regardez les paires de méthodes générées et un didacticiel devrait vous montrer comment l'utiliser.)
L'astuce est que ce class
n'est pas une définition en 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 attr_accessor
méthode est invoquée, ce qui modifie à son tour la classe actuelle - rappelez-vous le récepteur implicite:, self.attr_accessor
où se self
trouve l'objet de classe "ouvert" à ce stade.
Le besoin attr_accessor
et les amis, c'est bien:
Ruby, comme Smalltalk, n'autorise pas l'accès aux variables d'instance en dehors des méthodes 1 pour cet objet. Autrement dit, les variables d'instance ne sont pas accessibles sous la x.y
forme comme cela est courant dans disons Java ou même Python. En Ruby y
est toujours considéré comme un message à envoyer (ou "méthode à appeler"). Ainsi, les attr_*
méthodes créent des wrappers qui procurent un @variable
accès à l'instance via des méthodes créées dynamiquement.
Boilerplate suce
J'espère que cela clarifie certains des petits détails. Codage heureux.
1 Ce n'est pas strictement vrai et il existe des "techniques" à ce sujet , mais il n'y a pas de prise en charge de la syntaxe pour l'accès aux "variables d'instance publique".
attr_accessor
est (comme @pst l'a déclaré) juste une méthode. Ce qu'il fait, c'est 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
et enfin trouvée ici! Bien que cela ait résolu mon problème, mais je suis curieux de savoir où (livre / doc officiel) puis-je trouver un exemple d'implémentation comme celui-ci?
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 objet
Fondamentalement, ils falsifient des attributs de données accessibles au public, ce que Ruby n'a pas.
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
La plupart des réponses ci-dessus utilisent du code. Cette explication tente d'y répondre sans en utiliser aucune, via une analogie / histoire:
Les parties externes 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 gens à l'intérieur de la CIA. En d'autres termes, les personnes externes ne peuvent accéder à aucune information de la CIA. Mais parce qu'il n'est pas bon d'avoir une organisation qui est complètement secrète, certaines informations sont mises à la disposition du monde extérieur - seules choses que la CIA veut que tout le monde sache bien sûr: par exemple, le directeur de la CIA, à quel point ce département est respectueux de l'environnement à tous les autres départements du gouvernement, etc.
Si vous êtes en dehors de la CIA, vous ne pouvez accéder qu'aux informations qu'elle a mises à la disposition du public. Ou pour utiliser le langage de la CIA, vous ne pouvez accéder qu'aux informations "effacées".
Les informations que la CIA souhaite mettre à la disposition du grand public en dehors de la CIA sont appelées: attributs.
La signification des attributs de lecture et d'écriture:
Dans le cas de la CIA, la plupart des attributs sont en "lecture seule". Cela signifie que si vous êtes un parti extérieur à la CIA, vous pouvez demander: "qui est le directeur de la CIA?" et vous obtiendrez une réponse directe. Mais ce que vous ne pouvez pas faire avec les attributs "en lecture seule", c'est apporter des modifications dans la CIA. Par exemple, vous ne pouvez pas appeler et décider soudainement que vous voulez que Kim Kardashian soit le directeur, ou que vous voulez que Paris Hilton soit le commandant en chef.
Si les attributs vous ont donné un accès en "écriture", vous pouvez apporter des modifications si vous le souhaitez, 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 de poser des questions ou d'apporter des modifications aux organisations qui, autrement, ne laissent pas entrer de personnes externes, selon que les accesseurs sont des accesseurs en lecture ou en écriture.
Les objets à l'intérieur d'une classe peuvent facilement accéder les uns aux autres
Exactement la même chose avec les classes et votre capacité à accéder aux variables, propriétés et méthodes qu'elles contiennent. HTH! Toutes les questions, veuillez demander et j'espère que je peux clarifier.
Si vous connaissez le concept OOP, vous devez vous familiariser avec la méthode getter et setter. attr_accessor fait de même en Ruby.
Getter et Setter dans General Way
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"
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 à ce sujet, mais si vous cherchez plus de précisions, j'espère que ma réponse pourra vous aider.
Initialize, méthode
Initialize vous permet de définir des données sur une instance d'un objet lors de la création de l'instance plutôt que d'avoir à les définir sur une ligne distincte dans votre code chaque fois que vous créez une nouvelle instance de la classe.
class Person
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 passant Dennis à travers le paramètre dans Initialize. Si nous voulions définir le nom sans la méthode initialize, 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 setter attr_accessor à l'aide de person.name, plutôt que de définir les valeurs lors de l'initialisation de l'objet.
Les deux «méthodes» de faire ce travail, mais initialiser nous font gagner du temps et des lignes de code.
C'est le seul travail d'initialisation. Vous ne pouvez pas appeler initialize comme méthode. Pour obtenir réellement les valeurs d'un objet d'instance, vous devez utiliser des getters et setters (attr_reader (get), attr_writer (set) et attr_accessor (both)). Voir ci-dessous pour plus de détails à ce sujet.
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 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 «met example.item_name» et «example.quantity» renverront (ou «obtiendront») la valeur des paramètres qui ont été 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, sauf qu'elle nous permet d'économiser six lignes de code. Imaginez si vous aviez 5 autres états attribuables à la classe Item? Le code deviendrait rapidement long.
Setters, attr_writer: Ce qui m'a d'abord traversé avec les méthodes setter, c'est qu'à mes yeux, il semblait remplir une fonction identique à la méthode initialize. 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 objet lors de sa création.
Mais que se passe-t-il si vous souhaitez 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 définition. C'EST LA DIFFÉRENCE. Vous n'avez pas à «définir» un état particulier lorsque vous utilisez initialement la méthode attr_writer.
Le code ci-dessous est un exemple d'utilisation d'une méthode de définition pour déclarer la valeur item_name pour cette instance de la classe Item. Notez que nous continuons à utiliser la méthode getter attr_reader afin que nous puissions obtenir les valeurs et les imprimer à l'écran, juste au cas où vous voudriez tester le code par 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 nous faire 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 objets de nom_article 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 d'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'il a un attribut donné (par exemple, un nom) et donner à cet attribut une valeur tout d'un coup?"
Un peu plus généralisé, mais voici comment ça a cliqué pour moi:
Donné:
class Person
end
Nous n'avons pas défini Personne comme quelque chose qui peut avoir un nom ou tout autre attribut d'ailleurs.
Donc, si nous:
baby = Person.new
... et essayez de leur donner un nom ...
baby.name = "Ruth"
Nous obtenons une erreur parce que, dans Rubyland, une classe d'objet Personne n'est pas quelque chose qui est associée ou capable d'avoir un "nom" ... pour le moment!
MAIS nous pouvons utiliser n'importe laquelle des méthodes données (voir réponses précédentes) pour dire: "Une instance d'une classe Person ( baby
) peut maintenant avoir un attribut appelé 'nom', donc nous avons non seulement une façon syntaxique d'obtenir et définir ce nom, mais il est logique pour nous de le faire. "
Encore une fois, frapper 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 la classe Person qui trouvera son chemin vers ce fil.
Autrement dit, il 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
Donc
attr_accessor :v which means
attr_reader :v; attr_writer :v
sont équivalents pour définir un setter et un getter pour la classe.
Une autre façon de le comprendre est de comprendre quel code d'erreur il élimine en ayant 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 balance
ne sont pas, techniquement, une méthode , mais un attribut. La classe BankAccount n'a pas def owner
et 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 attributs comme si vous accédiez à une méthode via attr_accessor
!! D'où le motattr_accessor
. Attribut. Accesseur. Il accède aux attributs comme vous accéderiez à une méthode.
L'ajout attr_accessor :balance, :owner
vous permet de lire et d'écrire balance
et de owner
"méthode". Vous pouvez maintenant utiliser les 2 dernières méthodes.
$ bankie.balance
$ bankie.owner
Définit un attribut nommé pour ce module, où le nom est symbol.id2name, créant une variable d'instance (@name) et une méthode d'accès correspondante pour le lire. Crée également une méthode appelée nom = pour définir l'attribut.
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
Pour résumer un accesseur d'attribut aka attr_accessor vous donne deux méthodes gratuites.
Comme à Java, ils sont appelés getters et setters.
De nombreuses réponses ont montré de bons exemples, je vais donc être bref.
#the_attribute
et
# the_attribute =
Dans les anciens documents ruby, une balise de hachage # signifie une méthode. Il pourrait également inclure un préfixe de nom de classe ... MyClass # my_method
Je suis nouveau dans le rubis et je devais juste comprendre la bizarrerie suivante. Pourrait aider quelqu'un d'autre à l'avenir. Au final, c'est comme cela a été mentionné ci-dessus, où 2 fonctions (def myvar, def myvar =) obtiennent toutes deux implicitement l'accès à @myvar, mais ces méthodes peuvent être remplacées par des déclarations locales.
class Foo
attr_accessor 'myvar'
def initialize
@myvar = "A"
myvar = "B"
puts @myvar # A
puts myvar # B - myvar declared above overrides myvar method
end
def test
puts @myvar # A
puts myvar # A - coming from myvar accessor
myvar = "C" # local myvar overrides accessor
puts @myvar # A
puts myvar # C
send "myvar=", "E" # not running "myvar =", but instead calls setter for @myvar
puts @myvar # E
puts myvar # C
end
end
Les attributs sont des composants de classe accessibles depuis l'extérieur de l'objet. Ils sont connus comme propriétés dans de nombreux autres langages de programmation. Leurs valeurs sont accessibles en utilisant la "notation par points", comme dans nom_objet.nom_attribut. Contrairement à Python et à quelques autres langages, Ruby ne permet pas d'accéder directement aux variables d'instance depuis l'extérieur de l'objet.
class Car
def initialize
@wheels = 4 # This is an instance variable
end
end
c = Car.new
c.wheels # Output: NoMethodError: undefined method `wheels' for #<Car:0x00000000d43500>
Dans l'exemple ci-dessus, c est une instance (objet) de la classe Car. Nous avons essayé en vain de lire la valeur de la variable d'instance de roues depuis l'extérieur de l'objet. Ce qui s'est passé, c'est que Ruby a tenté d'appeler une méthode nommée roues dans l'objet c, mais aucune de ces méthodes n'a été définie. En bref, nom_objet.nom_attribut essaie d'appeler une méthode nommée nom_attribut dans l'objet. Pour accéder à la valeur de la variable roues de 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'accesseur. Dans le contexte général de programmation, la manière habituelle d'accéder à une variable d'instance depuis l'extérieur de l'objet est d'implémenter des méthodes d'accesseur, également appelées méthodes getter et setter.
Dans l'exemple suivant, nous avons ajouté des méthodes getter et setter à la classe Car pour accéder à la variable roues de l'extérieur de l'objet. Ce n'est pas la "manière Ruby" de définir les getters et 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 getter et setter dans d'autres langues. 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 la rend accessible en écriture et attr_acessor la 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'attribut roues sera lisible et inscriptible de l'extérieur de l'objet. Si au lieu de attr_accessor, nous avons utilisé attr_reader, ce serait en lecture seule. Si nous utilisions attr_writer, ce serait en écriture seule. Ces trois méthodes ne sont pas des getters et des setters en elles-mêmes mais, lorsqu'elles sont appelées, elles créent des méthodes getter et setter pour nous. Ce sont des méthodes qui génèrent dynamiquement (par programme) d'autres méthodes; cela s'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 requis dans les méthodes getter et setter. Par exemple, une méthode de définition peut avoir besoin de valider des données ou d'effectuer un calcul avant d'affecter une valeur à une variable d'instance.
Il est possible d'accéder (lire et écrire) aux variables d'instance depuis l'extérieur de l'objet, 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 ravages.
Hmmm. Beaucoup de bonnes réponses. Voici mes quelques centimes dessus.
attr_accessor
est une méthode simple qui nous aide à nettoyer ( SÉCHAGE ) les méthodes répétitivesgetter and setter
.
Afin que nous puissions nous concentrer davantage sur l'écriture de la logique métier et ne pas nous soucier des setters et des getters.
La fonctionnalité principale de attr_accessor par rapport aux autres est la capacité d'accéder aux données à partir d'autres fichiers.
Donc, vous auriez généralement attr_reader ou attr_writer mais la bonne nouvelle est que Ruby vous permet de combiner ces deux avec attr_accessor. Je pense que c'est ma méthode à emporter car elle est plus bien arrondie ou polyvalente. Aussi, gardez à l'esprit que dans Rails, cela est éliminé car il le fait pour vous dans le back-end. En d'autres termes: il vaut mieux utiliser attr_acessor par rapport aux deux autres parce que vous n'avez pas à vous soucier d'être précis, l'accesseur couvre tout cela. 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 vous a aidé!