Estou tendo dificuldades para entender attr_accessor
em Ruby .
Alguém pode me explicar isso?
git
não tem nada a ver com attr_accessor
. Git é um software de controle de versão, enquanto que attr_accessor
é um método em Ruby .
Estou tendo dificuldades para entender attr_accessor
em Ruby .
Alguém pode me explicar isso?
git
não tem nada a ver com attr_accessor
. Git é um software de controle de versão, enquanto que attr_accessor
é um método em Ruby .
Respostas:
Digamos que você tenha uma aula Person
.
class Person
end
person = Person.new
person.name # => no method error
Obviamente, nunca definimos método name
. Vamos fazer isso.
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
Ah, podemos ler o nome, mas isso não significa que podemos atribuir o nome. Esses são dois métodos diferentes. O primeiro é chamado de leitor e o último é chamado de escritor . Ainda não criamos o escritor, então vamos fazer isso.
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"
Impressionante. Agora podemos escrever e ler variáveis de instância @name
usando métodos reader e writer. Exceto que isso é feito com tanta frequência, por que perder tempo escrevendo esses métodos sempre? Nós podemos fazer isso mais fácil.
class Person
attr_reader :name
attr_writer :name
end
Mesmo isso pode se tornar repetitivo. Quando você quiser tanto leitor quanto escritor, use o acessador!
class Person
attr_accessor :name
end
person = Person.new
person.name = "Dennis"
person.name # => "Dennis"
Funciona da mesma maneira! E adivinhe: a variável de instância @name
em nosso objeto pessoal será definida como quando a fizemos manualmente, para que você possa usá-la em outros métodos.
class Person
attr_accessor :name
def greeting
"Hello #{@name}"
end
end
person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"
É isso aí. Para entender como attr_reader
, attr_writer
e attr_accessor
métodos realmente geram métodos para você, leia outras respostas, livros, documentos em ruby.
attr_accessor
é um método chamado na classe atual e :name
é um parâmetro que você passa para esse método. Não é uma sintaxe especial, é uma chamada de método simples. Se você desse uma @name
variável, não faria sentido, porque @name conteria nil
. Então seria como escrever attr_accessor nil
. Você não está passando uma variável que ela precisa criar, está passando o nome que deseja que a variável seja chamada.
name
e variável @name
não são a mesma coisa. Não os confunda. Você tem uma variável de instância @name
em sua classe e define attr_reader :name
para poder lê-la de fora. Sem, attr_reader
não há uma maneira simples de acessar @name
fora da sua turma.
attr_accessor é apenas um método . (O link deve fornecer mais informações sobre como ele funciona - observe os pares de métodos gerados e um tutorial deve mostrar como usá-lo.)
O truque é que nãoclass
é uma definição em Ruby (é "apenas uma definição" em linguagens como C ++ e Java), mas é uma expressão que avalia . É durante essa avaliação quando o attr_accessor
método é chamado, que por sua vez modifica a classe atual - lembre-se do receptor implícito:, self.attr_accessor
onde self
está o objeto de classe "aberto" neste momento.
A necessidade de attr_accessor
e os amigos são:
Ruby, como Smalltalk, não permite que variáveis de instância sejam acessadas fora dos métodos 1 para esse objeto. Ou seja, as variáveis de instância não podem ser acessadas no x.y
formulário, como é comum, por exemplo, Java ou mesmo Python. Em Ruby y
é sempre tomada como uma mensagem para enviar (ou "método para chamar"). Assim, os attr_*
métodos criam wrappers que @variable
acessam a instância por meio de métodos criados dinamicamente.
Boilerplate é uma merda
Espero que isso esclareça alguns dos pequenos detalhes. Feliz codificação.
1 Isso não é estritamente verdadeiro e existem algumas "técnicas" em torno disso , mas não há suporte à sintaxe para acesso à "variável de instância pública".
attr_accessor
é (como @pst afirmou) apenas um método. O que ele faz é criar mais métodos para você.
Portanto, este código aqui:
class Foo
attr_accessor :bar
end
é equivalente a este código:
class Foo
def bar
@bar
end
def bar=( new_value )
@bar = new_value
end
end
Você pode escrever esse tipo de método em 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
e finalmente encontrei aqui! Embora tenha resolvido meu problema, mas estou curioso para saber onde (livro / documento oficial) posso encontrar um exemplo de implementação como este?
attr_accessor
é muito simples:
attr_accessor :foo
é um atalho para:
def foo=(val)
@foo = val
end
def foo
@foo
end
nada mais é do que um getter / setter para um objeto
Basicamente, eles falsificam atributos de dados acessíveis ao público, que Ruby não possui.
É apenas um método que define métodos getter e setter para variáveis de instância. Um exemplo de implementação seria:
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
A maioria das respostas acima usa código. Esta explicação tenta responder sem usar nenhuma, por meio de uma analogia / história:
As partes externas não podem acessar segredos internos da CIA
Vamos imaginar um lugar realmente secreto: a CIA. Ninguém sabe o que está acontecendo na CIA além das pessoas dentro da CIA. Em outras palavras, pessoas externas não podem acessar nenhuma informação na CIA. Mas como não é bom ter uma organização que é completamente secreta, certas informações são disponibilizadas para o mundo exterior - apenas as coisas que a CIA deseja que todos saibam, é claro: por exemplo, o diretor da CIA, como esse departamento é ecológico para todos os outros departamentos governamentais etc. Outras informações: por exemplo, quem são seus agentes secretos no Iraque ou no Afeganistão - esse tipo de coisa provavelmente permanecerá em segredo pelos próximos 150 anos.
Se você estiver fora da CIA, poderá acessar apenas as informações disponibilizadas ao público. Ou, para usar a linguagem da CIA, você pode acessar apenas as informações "limpas".
As informações que a CIA deseja disponibilizar ao público em geral fora da CIA são denominadas: atributos.
O significado dos atributos de leitura e gravação:
No caso da CIA, a maioria dos atributos é "somente leitura". Isso significa que, se você é uma parte externa à CIA, pode perguntar: "quem é o diretor da CIA?" e você receberá uma resposta direta. Mas o que você não pode fazer com os atributos "somente leitura" é fazer alterações na CIA. por exemplo, você não pode fazer uma ligação e decidir subitamente que deseja que Kim Kardashian seja o diretor ou que Paris Hilton seja o comandante em chefe.
Se os atributos fornecerem acesso "de gravação", você poderá fazer alterações, se desejar, mesmo se estiver fora. Caso contrário, a única coisa que você pode fazer é ler.
Em outras palavras, os acessadores permitem que você faça consultas ou faça alterações em organizações que de outra forma não permitem a entrada de pessoas externas, dependendo de os acessadores serem acessadores de leitura ou gravação.
Objetos dentro de uma classe podem acessar-se facilmente
Exatamente o mesmo com as classes e sua capacidade de acessar variáveis, propriedades e métodos dentro delas. HTH! Qualquer dúvida, por favor, pergunte e espero que eu possa esclarecer.
Se você está familiarizado com o conceito de POO, deve familiarizar-se com o método getter e setter. attr_accessor faz o mesmo em Ruby.
Getter e Setter de maneira geral
class Person
def name
@name
end
def name=(str)
@name = str
end
end
person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"
Método Setter
def name=(val)
@name = val
end
Método Getter
def name
@name
end
Método Getter e Setter em Ruby
class Person
attr_accessor :name
end
person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
Também enfrentei esse problema e escrevi uma resposta um tanto demorada para essa pergunta. Já existem ótimas respostas sobre isso, mas quem procura mais esclarecimentos, espero que minha resposta possa ajudar
Método de inicialização
Initialize permite que você defina dados para uma instância de um objeto após a criação da instância, em vez de precisar defini-los em uma linha separada no seu código toda vez que você cria uma nova instância da classe.
class Person
def initialize(name)
@name = name
end
def greeting
"Hello #{@name}"
end
end
person = Person.new("Denis")
puts person.greeting
No código acima, estamos definindo o nome “Denis” usando o método initialize passando Dennis pelo parâmetro em Initialize. Se quiséssemos definir o nome sem o método initialize, poderíamos fazer o seguinte:
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
No código acima, definimos o nome chamando o método attr_accessor setter usando person.name, em vez de definir os valores na inicialização do objeto.
Os dois "métodos" de fazer esse trabalho, mas inicializar, economizam tempo e linhas de código.
Este é o único trabalho de inicialização. Você não pode chamar a inicialização como um método. Para realmente obter os valores de um objeto de instância, você precisa usar getters e setters (attr_reader (get), attr_writer (set) e attr_accessor (ambos)). Veja abaixo mais detalhes sobre esses.
Getters, Setters (attr_reader, attr_writer, attr_accessor)
Getters, attr_reader: O objetivo inteiro de um getter é retornar o valor de uma variável de instância específica. Visite o código de exemplo abaixo para obter detalhes sobre isso.
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
No código acima, você está chamando os métodos "item_name" e "quantidade" na instância do item "exemplo". O “puts example.item_name” e “example.quantity” retornarão (ou “obterão”) o valor dos parâmetros que foram passados para o “exemplo” e os exibirão na tela.
Felizmente, em Ruby, existe um método inerente que nos permite escrever esse código de forma mais sucinta; o método attr_reader. Veja o código abaixo;
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
Essa sintaxe funciona exatamente da mesma maneira, mas nos salva seis linhas de código. Imagine se você tivesse mais 5 estados atribuíveis à classe Item? O código iria demorar muito rapidamente.
Setters, attr_writer: O que me impressionou no início com os métodos setter é que, aos meus olhos, parecia desempenhar uma função idêntica ao método inicializar. Abaixo, explico a diferença com base no meu entendimento;
Como mencionado anteriormente, o método initialize permite definir os valores para uma instância de um objeto na criação do objeto.
Mas e se você quiser definir os valores posteriormente, após a instância ter sido criada, ou alterá-los após a inicialização? Este seria um cenário em que você usaria um método setter. Essa é a diferença. Você não precisa "definir" um estado específico quando estiver usando o método attr_writer inicialmente.
O código abaixo é um exemplo de uso de um método setter para declarar o valor item_name para esta instância da classe Item. Observe que continuamos a usar o método getter attr_reader para que possamos obter os valores e imprimi-los na tela, caso você queira testar o código por conta própria.
class Item
attr_reader :item_name
def item_name=(str)
@item_name = (str)
end
end
O código abaixo é um exemplo de uso do attr_writer para encurtar novamente nosso código e economizar tempo.
class Item
attr_reader :item_name
attr_writer :item_name
end
item = Item.new
puts item.item_name = "TV"
O código abaixo é uma reiteração do exemplo de inicialização acima de onde estamos usando initialize para definir o valor dos objetos item_name na criação.
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: Executa as funções de attr_reader e attr_writer, economizando mais uma linha de código.
Eu acho que parte do que confunde novos rubiistas / programadores (como eu) é:
"Por que não posso simplesmente dizer à instância que ele possui algum atributo (por exemplo, nome) e atribuir um valor a esse atributo de uma só vez?"
Um pouco mais generalizado, mas foi assim que clicou para mim:
Dado:
class Person
end
Não definimos Person como algo que pode ter um nome ou qualquer outro atributo para esse assunto.
Então, se nós:
baby = Person.new
... e tente dar um nome a eles ...
baby.name = "Ruth"
Recebemos um erro porque, em Rubyland, uma classe de objeto Person não é algo associado ou capaz de ter um "nome" ... ainda!
MAS podemos usar qualquer um dos métodos fornecidos (consulte as respostas anteriores) como uma maneira de dizer: "Uma instância de uma classe Person ( baby
) agora pode ter um atributo chamado 'name'; portanto, não temos apenas uma maneira sintática de obter e definindo esse nome, mas faz sentido para nós ".
Novamente, respondendo a essa pergunta de um ângulo um pouco diferente e mais geral, mas espero que isso ajude a próxima instância da classe Person que encontra seu caminho para esse segmento.
Simplificando, ele definirá um setter e um getter para a classe.
Observe que
attr_reader :v is equivalant to
def v
@v
end
attr_writer :v is equivalant to
def v=(value)
@v=value
end
assim
attr_accessor :v which means
attr_reader :v; attr_writer :v
são equivalentes para definir um setter e um getter para a classe.
Outra maneira de entender isso é descobrir qual código de erro ele elimina por ter attr_accessor
.
Exemplo:
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
Os seguintes métodos estão disponíveis:
$ bankie = BankAccout.new("Iggy")
$ bankie
$ bankie.deposit(100)
$ bankie.withdraw(5)
Os seguintes métodos geram erro:
$ bankie.owner #undefined method `owner'...
$ bankie.balance #undefined method `balance'...
owner
e balance
não são, tecnicamente, um método , mas um atributo. A classe BankAccount não possui def owner
e def balance
. Nesse caso, você pode usar os dois comandos abaixo. Mas esses dois métodos não estão lá. No entanto, você pode acessar atributos como se você tivesse acessar um método via attr_accessor
!! Daí a palavraattr_accessor
. Atributo. Accessor. Ele acessa atributos como você acessaria um método.
A adição attr_accessor :balance, :owner
permite ler e escrever balance
e owner
"método". Agora você pode usar os dois últimos métodos.
$ bankie.balance
$ bankie.owner
Define um atributo nomeado para este módulo, em que o nome é symbol.id2name, criando uma variável de instância (@name) e um método de acesso correspondente para lê-lo. Também cria um método chamado name = para definir o atributo.
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
Resumir um acessador de atributo, também conhecido como attr_accessor, oferece dois métodos gratuitos.
Como em Java, eles são chamados de getters e setters.
Muitas respostas mostraram bons exemplos, por isso vou ser breve.
#the_attribute
e
# the_attribute =
Nos documentos antigos do ruby, um hash tag # significa um método. Também pode incluir um prefixo de nome de classe ... MyClass # my_method
Eu sou novo no Ruby e tive que lidar apenas com a compreensão da seguinte estranheza. Pode ajudar alguém no futuro. No final, é como foi mencionado acima, onde 2 funções (def myvar, def myvar =) ficam implicitamente para acessar @myvar, mas esses métodos podem ser substituídos por declarações locais.
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
Atributos são componentes de classe que podem ser acessados de fora do objeto. Eles são conhecidos como propriedades em muitas outras linguagens de programação. Seus valores são acessíveis usando a "notação de ponto", como em object_name.attribute_name. Diferentemente do Python e de algumas outras linguagens, o Ruby não permite que variáveis da instância sejam acessadas diretamente de fora do objeto.
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>
No exemplo acima, c é uma instância (objeto) da classe Car. Tentamos, sem sucesso, ler o valor da variável de instância wheel de fora do objeto. O que aconteceu foi que Ruby tentou chamar um método chamado wheel dentro do objeto c, mas nenhum método foi definido. Em resumo, object_name.attribute_name tenta chamar um método chamado attribute_name dentro do objeto. Para acessar o valor da variável wheel de fora, precisamos implementar um método de instância com esse nome, que retornará o valor dessa variável quando for chamado. Isso é chamado de método acessador. No contexto geral de programação, a maneira usual de acessar uma variável de instância de fora do objeto é implementar métodos acessadores, também conhecidos como métodos getter e setter.
No exemplo a seguir, adicionamos métodos getter e setter à classe Car para acessar a variável wheel de fora do objeto. Esta não é a "maneira Ruby" de definir getters e setters; serve apenas para ilustrar o que os métodos getter e setter fazem.
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
O exemplo acima funciona e um código semelhante é comumente usado para criar métodos getter e setter em outros idiomas. No entanto, o Ruby fornece uma maneira mais simples de fazer isso: três métodos internos chamados attr_reader, attr_writer e attr_acessor. O método attr_reader torna uma variável de instância legível do lado de fora, attr_writer a torna gravável e attr_acessor a torna legível e gravável.
O exemplo acima pode ser reescrito assim.
class Car
attr_accessor :wheels
end
f = Car.new
f.wheels = 4
f.wheels # Output: => 4
No exemplo acima, o atributo wheel será legível e gravável de fora do objeto. Se, em vez de attr_accessor, usamos attr_reader, seria somente leitura. Se usássemos attr_writer, seria somente gravação. Esses três métodos não são getters e setters em si mesmos, mas, quando chamados, criam métodos getter e setter para nós. São métodos que geram dinamicamente (programaticamente) outros métodos; isso é chamado de metaprogramação.
O primeiro exemplo (mais longo), que não emprega os métodos internos do Ruby, deve ser usado apenas quando código adicional for necessário nos métodos getter e setter. Por exemplo, um método setter pode precisar validar dados ou fazer algum cálculo antes de atribuir um valor a uma variável de instância.
É possível acessar (ler e escrever) variáveis de instância de fora do objeto, usando os métodos internos instance_variable_get e instance_variable_set. No entanto, isso raramente é justificável e geralmente é uma péssima idéia, já que contornar o encapsulamento tende a causar todo tipo de confusão.
Hummm. Muitas boas respostas. Aqui estão meus poucos centavos.
attr_accessor
é um método simples que nos ajuda a limpar ( secar ) os métodos repetidosgetter and setter
.
Para que possamos nos concentrar mais em escrever a lógica de negócios e não nos preocupar com os levantadores e os levantadores.
A principal funcionalidade do attr_accessor sobre as outras é a capacidade de acessar dados de outros arquivos.
Então você normalmente teria attr_reader ou attr_writer, mas a boa notícia é que Ruby permite combinar esses dois com o attr_accessor. Penso nisso como o meu método de ir, porque é mais bem-arredondado ou versátil. Além disso, lembre-se de que, no Rails, isso é eliminado porque faz isso por você no back-end. Portanto, em outras palavras: é melhor usar o attr_acessor em relação aos outros dois porque não precisa se preocupar em ser específico, o acessador cobre tudo. Eu sei que essa é uma explicação mais geral, mas me ajudou como iniciante.
Espero que isso tenha ajudado!