O que é o attr accessor em Ruby?
18 answers
class Person
end
person = Person.new
person.name # => no method error
Obviamente, nunca definimos o método. 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
Aha, podemos ler o nome, mas isso não significa que podemos atribuir o nome. São dois métodos diferentes. O primeiro é chamado leitor e o segundo é chamado escritor . Ainda não criámos o escritor, por isso 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"
Fantástico. Agora podemos escrever e ler a variável instância @name
usando métodos de leitura e escrita. Excepto que isto é feito com tanta frequência, porquê perder tempo a escrever estes métodos todas as vezes? Podemos fazê-lo mais facilmente.
class Person
attr_reader :name
attr_writer :name
end
Até isto pode tornar-se repetitivo. Quando você quer tanto leitor e escritor basta usar acessor!
class Person
attr_accessor :name
end
person = Person.new
person.name = "Dennis"
person.name # => "Dennis"
Funciona da mesma maneira! E adivinha: a variável de instância @name
em nosso objeto pessoal será definida exatamente como quando 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. Para entender como attr_reader
, attr_writer
, e attr_accessor
métodos na verdade gerar métodos para você, ler outras respostas, livros, Ruby docs.
O acessor é apenas um método . (O link deve fornecer mais informações sobre como ele funciona - veja os pares de métodos gerados, e um tutorial deve mostrar-lhe como usá-lo.)
O truque é que class
é não é uma definição em Ruby (é "apenas uma definição" em linguagens como C++ e Java), mas é um expressão que avalia. É durante esta avaliação que o método attr_accessor
é invocado que, por sua vez, modifica a classe actual-lembre-se do receptor implícito: self.attr_accessor
, onde self
é o objecto de classe "aberto" neste ponto.
A necessidade de attr_accessor
e amigos, é, bem:
O Ruby, como o Smalltalk, não permite que variáveis de instância sejam acessadas fora dos métodos1 por esse objecto. Ou seja, variáveis de instância não podem ser acessadas na forma
x.y
Como é comum em say, Java ou mesmo Python. Em Rubyy
é sempre tomada como uma mensagem a enviar (ou "método a chamar"). Assim os métodosattr_*
criam invólucros que proxy o acesso à instância@variable
através de métodos criados dinamicamente.O Boilerplate é uma treta.
1 isto não é estritamente verdade e existem algumas "técnicas" em torno deste , mas não há suporte de sintaxe para o acesso de" instância pública variável".
attr_accessor
é (como @pst afirmou) apenas um método. O que ele faz é criar mais métodos para você.
Então 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
Podes escrever este 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
é muito simples:
attr_accessor :foo
É um atalho para:
def foo=(val)
@foo = val
end
def foo
@foo
end
Não é nada mais do que um getter / setter para um objecto
É apenas um método que define os métodos de getter e setter por exemplo variáveis. 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
Inicializar O Método
Inicializar permite-lhe definir os dados para uma instância de um objecto após a criação da instância, em vez de ter de Os definir numa linha separada no seu código cada vez que cria uma nova instância da 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
No código acima estamos definir o nome "Denis" usando o método inicializar, passando Dennis através do parâmetro in inicialize. Se quiséssemos definir o nome sem o método de inicialização poderíamos fazê-lo assim:
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 usando o método de identificação do utilizador. person.name, ao invés de definir os valores após a inicialização do objeto.
Ambos os "métodos" de fazer este trabalho, mas a inicialização poupa-nos tempo e linhas de código.
Este é o ... é o único trabalho de inicialização. Você não pode invocar inicializar como um método. Para obter efectivamente os valores de um objecto de instância, é necessário utilizar os seus assinantes e os seus assinantes ("attr_reader", "attr_writer" ("set") e "attr_acessor" ("ambos"). Veja abaixo para mais detalhes sobre estes.Getters, Setters (attr_reader, attr_writer, attr_accessor)
([8]) locutor: o objectivo de um locutor é devolver o valor de uma dada variável de instância. Visite o código de amostra abaixo para obter uma discriminação 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 " põe exemplo.item_name " e " example.quantidade "irá retornar (ou" obter") o valor para os parâmetros que foram passados para o" exemplo " e exibi-los para a tela.
Felizmente, em Ruby existe um método inerente que nos permite escrever este código de forma mais sucinta: o método de leitura rápida. Ver 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
Esta sintaxe funciona exactamente como da mesma forma, só que nos poupa seis linhas de código. Imagine se você tivesse mais 5 estado atribuível à classe de itens? O código demoraria muito rapidamente.
O que me passou pela cabeça com métodos de montagem é que, aos meus olhos, parecia desempenhar uma função idêntica ao método de inicialização. Abaixo eu explico a diferença com base no meu entendimento;Como indicado anteriormente, o método inicializar permite-lhe definir os valores para uma instância de um objecto sobre um objecto criacao.
Mas e se você quiser definir os valores mais tarde, depois que a instância foi criada, ou alterá-los depois que eles foram inicializados? Este seria um cenário onde você usaria um método setter. ESSA É A DIFERENÇA. Você não tem que "definir" um estado em particular quando você está usando o método attr_writer inicialmente.
O código abaixo é um exemplo de usar um método de setter para declarar o valor item_ nome para esta instância da classe de itens. Note - se que continuamos a use o método getter attr_reader para que possamos obter os valores e imprimi-los para a tela, no caso de você quiser 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 que se segue é um exemplo de Utilização da Seguradora para encurtar mais uma vez o nosso código e poupar-nos 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 inicializar acima de onde estamos usando inicialize para definir o valor dos objetos do item_ nome após a 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
Serviço das Publicações Oficiais das Comunidades Europeias ladrão e segurador, poupando-lhe mais uma linha de código.
"Por que não posso dizer à instância que ela tem algum atributo dado (por exemplo, nome) e dar a esse atributo um valor tudo de uma só vez?"
Um pouco mais generalizado, mas foi assim que me pareceu:Indicado:
class Person
end
Ainda não definimos a pessoa como algo que pode ter um nome ou qualquer outro atributo para isso.
Então, se nós ...baby = Person.new
...e tenta dar-lhes um nome...
baby.name = "Ruth"
Temos um erro porque, no Rubyland, uma classe de pessoa de objeto não é algo que esteja associado ou seja capaz de ter um "nome" ... ainda!
, MAS podemos usar qualquer uma das dada métodos (vide respostas anteriores) como uma forma de dizer, "Uma instância de uma classe Pessoa (baby
) pode agora tem um atributo chamado "nome", portanto, não temos apenas um sintática forma de obtenção e definição de nome, mas ele faz sentido para a gente fazer entao."
Se está familiarizado com o conceito de OOP, deve estar familiarizado com o método getter e setter. o acessor faz o mesmo em Ruby.
Getter e Setter em 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 De Configuração
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"
A maioria das respostas acima usam código. Esta explicação tenta responder sem usar qualquer código:
Explicação por analogia
Partes externas não podem aceder a segredos internos da CIA.
Vamos imaginar um lugar realmente secreto: a CIA. Ninguém sabe o que está a acontecer na CIA, além das pessoas dentro da CIA. Por outras palavras, as pessoas externas não podem aceder a qualquer informação na CIA. Mas porque não é bom ter uma organização isso é completamente secreto, certas informações são disponibilizadas ao mundo exterior - apenas coisas que a CIA quer que todos saibam, é claro: por exemplo, o diretor da CIA, como este departamento é amigo do ambiente em comparação com todos os outros departamentos do governo, etc. Outras informações: por exemplo, quem são os seus agentes secretos no Iraque ou no Afeganistão - este tipo de coisas provavelmente permanecerá um segredo para os próximos 150 anos.
Se você está fora da CIA você só pode acesse as informações que disponibilizou ao público. Ou para usar a linguagem da CIA, só se pode aceder a informações "limpas".
As informações que a CIA quer disponibilizar ao público em geral fora da CIA são chamadas: Atributos.
O significado dos atributos de leitura e escrita:
No caso da CIA, a maioria dos atributos são "apenas para leitura". Isto significa que se for uma parte a CIA, podes perguntar: quem é o director da CIA?"e terás uma resposta directa. Mas o que você não pode fazer com atributos "só de leitura" é fazer mudanças na CIA. por exemplo, não se pode fazer um telefonema e, de repente, decidir que quer que Kim Kardashian seja o Director, ou que quer que Paris Hilton seja o Comandante Supremo.
-
Se os atributos lhe deram acesso de "escrita" , então você pode fazer alterações se quiser, mesmo que você estávamos lá fora. Caso contrário, a única coisa que podes fazer é ler.
Por outras palavras, os acessores permitem-lhe fazer perguntas, ou fazer alterações, a organizações que, de outro modo, não deixam entrar pessoas externas, dependendo se os acessores são lidos ou escrevem acessores.
Objetos dentro de uma classe podem facilmente acessar uns aos outros
- Por outro lado, se já estivesse dentro da CIA, podia facilmente ligar para o seu agente da CIA. Kabul e pergunta-lhe se quer beber uma cerveja com o Informador de Kabul depois do trabalho. Mas se você estiver fora da CIA, você simplesmente não terá acesso: você não será capaz de saber quem eles são (acesso de leitura), e você não será capaz de mudar sua missão (acesso de escrita).
Exactamente a mesma coisa com as classes e a sua capacidade de aceder a variáveis, propriedades e métodos dentro delas. HTH! Qualquer pergunta, por favor, faça e espero poder esclarecer.
Simplificando, irá definir um setter e getter para a classe.
Note que
attr_reader :v is equivalant to
def v
@v
end
attr_writer :v is equivalant to
def v=(value)
@v=value
end
Por isso
attr_accessor :v which means
attr_reader :v; attr_writer :v
São equivalentes para definir um setter e getter para a classe.
Simplesmente attr-accessor
cria os métodos getter
e setter
para os atributos indicados
Outra maneira de entender é descobrir que código de erro elimina tendo 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
Estão disponíveis os seguintes métodos:
$ bankie = BankAccout.new("Iggy")
$ bankie
$ bankie.deposit(100)
$ bankie.withdraw(5)
Os seguintes métodos lançam erros:
$ 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 tem def owner
e def balance
. Se isso acontecer, então você pode usar os dois comandos abaixo. Mas esses dois métodos não existem. No entanto, você pode access atributos como se tivesses access um método via attr_accessor
!! daí a palavra attr_accessor
. Atributo. Descritor. Ele acede a atributos como você teria acesso a um método.
Adicionar attr_accessor :balance, :owner
permite-lhe ler e escrever balance
e owner
"método". Agora você pode usar os últimos dois métodos.
$ bankie.balance
$ bankie.owner
Define um atributo nomeado para este módulo, onde o nome é symbol.id2name, criando uma variável de instância (@name) e um método de acesso correspondente para o ler. Também cria um método chamado NOME= para definir o atributo.
module Mod
attr_accessor(:one, :two)
end
Mod.instance_methods.sort #=> [:one, :one=, :two, :two=]
Muitas respostas mostraram bons exemplos, por isso vou ser breve.
#the_ attribute
E
#the_ attribute=
No antigo ruby docs uma etiqueta de hash # significa um método. Ele também pode incluir um prefixo de nome de classe... MyClass # my_method
Atributos e métodos de acesso
Os atributos são componentes de classe que podem ser acedidos fora do objecto. Eles são conhecidos como propriedades em muitas outras linguagens de programação. Seus valores são acessíveis usando a "notação dot", como no object_name.nome de atribuição. Ao contrário de Python e algumas outras linguagens, Ruby não permite que variáveis de 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) do carro classe. Nós tentamos sem sucesso ler o valor da variável de instância de rodas de fora do objeto. O que aconteceu foi que Ruby tentou chamar um método chamado rodas dentro do objeto c, mas nenhum desses métodos foi definido. Resumindo, nome do objecto.o attribute_name tenta chamar um método chamado attribute_name dentro do objeto. Para acessar o valor da variável rodas a partir do exterior, precisamos implementar um método de instância por esse nome, que irá devolver o valor dessa variável quando chamado. Chama-se Método de acesso. No contexto de programação geral, a maneira usual de acessar uma variável de instância de fora do objeto é implementar métodos de accessor, também conhecidos como métodos getter e setter. Um getter permite que o valor de uma variável definida dentro de uma classe seja lido do lado de fora e um setter permite que seja escrito do lado de fora.
No seguinte exemplo, adicionámos métodos de getter e setter à classe de carros para aceder à variável de rodas a partir do exterior. objecto. Esta não é a" maneira Ruby " de definir getters e setters; ela serve apenas para ilustrar o que getter e setter métodos 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 similar é comumente usado para criar métodos getter e setter em outras línguas. No entanto, a Ruby oferece uma forma mais simples de o fazer: três métodos incorporados, denominados "extra-terrestre", "extra-terrestre" e "extra-terrestre". O método attr_reader torna uma instância legível por terceiros, tornando-a escriturável, e o acessor torna-o 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 wheels será legível e gravável de fora do objeto. Se em vez de um acessor, usássemos um leitor, seria apenas para leitura. Se usássemos um segurador, seria apenas para escrever. Esses três métodos não são getters e setters em si mesmos, mas, quando chamados, eles criam getter e setter métodos para nós. São métodos que dynamically (programmatically) generate other methods; that's called metaprogramming.
O primeiro exemplo (mais longo), que não emprega os métodos embutidos da Ruby, só deve ser usado quando for necessário um código adicional nos métodos getter e setter. Por exemplo, um método de setter pode precisar validar dados ou fazer algum cálculo antes de atribuir um valor a uma variável de instância.
É possível aceder (ler e escrever) variáveis de instância de fora do objecto, usando o instance_variable_get e instance_ variable_ set embutidos. No entanto, isso raramente é justificável e geralmente uma má ideia, já que contornar encapsulação tende a causar todo tipo de caos.
Hmmm. Muitas boas respostas. Aqui estão os meus poucos cêntimos.
attr_accessor
é um método simples que nos ajuda a limpar [[[8]}a seco ] até à repetiçãogetter and setter
métodos.Para que possamos nos concentrar mais em escrever lógica de negócios e não nos preocupar com os setters e getters.
Por isso, normalmente terias um ladrão ou um escritor, mas a boa notícia é que a Ruby te deixa combinar estes dois com um acessor. Eu penso nisso como o meu método de ir porque é mais bem arredondado ou versátil. Além disso, peep em mente que em trilhos, isso é eliminado porque ele faz isso para você na parte de trás. Por outras palavras,: é melhor usares um acessor em vez dos outros dois, porque não tens de te preocupar em ser específico, o acessor cobre tudo. Sei que é mais uma explicação geral, mas ajudou-me como principiante. Espero que isto ajude!