class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
me dá o erro:
SyntaxError: erro dinâmico de atribuição constante
Por que isso é considerado uma constante dinâmica? Estou apenas atribuindo uma string a ele.
class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
me dá o erro:
SyntaxError: erro dinâmico de atribuição constante
Por que isso é considerado uma constante dinâmica? Estou apenas atribuindo uma string a ele.
Respostas:
Seu problema é que, toda vez que você executa o método, está atribuindo um novo valor à constante. Isso não é permitido, pois torna a constante não constante; mesmo que o conteúdo da string seja o mesmo (no momento, de qualquer maneira), o próprio objeto da string é diferente sempre que o método é chamado. Por exemplo:
def foo
p "bar".object_id
end
foo #=> 15779172
foo #=> 15779112
Talvez se você explicou seu caso de uso - por que deseja alterar o valor de uma constante em um método - poderíamos ajudá-lo com uma melhor implementação.
Talvez você prefira ter uma variável de instância na classe?
class MyClass
class << self
attr_accessor :my_constant
end
def my_method
self.class.my_constant = "blah"
end
end
p MyClass.my_constant #=> nil
MyClass.new.my_method
p MyClass.my_constant #=> "blah"
Se você realmente deseja alterar o valor de uma constante em um método, e sua constante é uma String ou uma Matriz, você pode 'trapacear' e usar o #replace
método para fazer com que o objeto adquira um novo valor sem realmente alterar o objeto:
class MyClass
BAR = "blah"
def cheat(new_bar)
BAR.replace new_bar
end
end
p MyClass::BAR #=> "blah"
MyClass.new.cheat "whee"
p MyClass::BAR #=> "whee"
def initialize(db,user,password) DB=Sequel.connect("postgres://#{user}:#{password}@localhost/#{db}") end
. É um daqueles casos em que Ruby não tem um caminho simples.
@variable
), não uma constante. Caso contrário, você seria redesignado DB
toda vez que instanciasse uma nova instância dessa classe.
Sequel.connect
a uma constante chamada DB . De fato, a documentação diz explicitamente que isso é apenas uma recomendação. Isso não parece uma restrição externa para mim.
Como as constantes no Ruby não devem ser alteradas, o Ruby o desencoraja de atribuir a elas partes do código que podem ser executadas mais de uma vez, como métodos internos.
Sob circunstâncias normais, você deve definir a constante dentro da própria classe:
class MyClass
MY_CONSTANT = "foo"
end
MyClass::MY_CONSTANT #=> "foo"
Se, por algum motivo, você realmente precisar definir uma constante dentro de um método (talvez para algum tipo de metaprogramação), poderá usar const_set
:
class MyClass
def my_method
self.class.const_set(:MY_CONSTANT, "foo")
end
end
MyClass::MY_CONSTANT
#=> NameError: uninitialized constant MyClass::MY_CONSTANT
MyClass.new.my_method
MyClass::MY_CONSTANT #=> "foo"
Novamente, porém, const_set
não é algo que você realmente precise recorrer em circunstâncias normais. Se você não tiver certeza se deseja realmente atribuir as constantes dessa maneira, considere uma das seguintes alternativas:
Variáveis de classe se comportam como constantes de várias maneiras. São propriedades em uma classe e são acessíveis nas subclasses da classe em que estão definidas.
A diferença é que as variáveis de classe devem ser modificáveis e, portanto, podem ser atribuídas a métodos internos sem problemas.
class MyClass
def self.my_class_variable
@@my_class_variable
end
def my_method
@@my_class_variable = "foo"
end
end
class SubClass < MyClass
end
MyClass.my_class_variable
#=> NameError: uninitialized class variable @@my_class_variable in MyClass
SubClass.my_class_variable
#=> NameError: uninitialized class variable @@my_class_variable in MyClass
MyClass.new.my_method
MyClass.my_class_variable #=> "foo"
SubClass.my_class_variable #=> "foo"
Atributos de classe são uma espécie de "variável de instância em uma classe". Eles se comportam um pouco como variáveis de classe, exceto que seus valores não são compartilhados com subclasses.
class MyClass
class << self
attr_accessor :my_class_attribute
end
def my_method
self.class.my_class_attribute = "blah"
end
end
class SubClass < MyClass
end
MyClass.my_class_attribute #=> nil
SubClass.my_class_attribute #=> nil
MyClass.new.my_method
MyClass.my_class_attribute #=> "blah"
SubClass.my_class_attribute #=> nil
SubClass.new.my_method
SubClass.my_class_attribute #=> "blah"
E, para completar, eu provavelmente devo mencionar: se você precisar atribuir um valor que só pode ser determinado após a instanciação da sua classe, há uma boa chance de você estar realmente procurando por uma variável de instância antiga simples.
class MyClass
attr_accessor :instance_variable
def my_method
@instance_variable = "blah"
end
end
my_object = MyClass.new
my_object.instance_variable #=> nil
my_object.my_method
my_object.instance_variable #=> "blah"
MyClass.new.instance_variable #=> nil
No Ruby, qualquer variável cujo nome comece com uma letra maiúscula é uma constante e você pode atribuir a ela apenas uma vez. Escolha uma destas alternativas:
class MyClass
MYCONSTANT = "blah"
def mymethod
MYCONSTANT
end
end
class MyClass
def mymethod
my_constant = "blah"
end
end
As constantes em ruby não podem ser definidas dentro de métodos. Veja as notas na parte inferior desta página, por exemplo
Você não pode nomear uma variável com letras maiúsculas ou o Ruby assumirá sua constante e desejará que ela mantenha seu valor constante; nesse caso, alterar seu valor seria um erro "erro de atribuição dinâmica constante". Com minúsculas deve ficar bem
class MyClass
def mymethod
myconstant = "blah"
end
end
Ruby não gosta que você esteja atribuindo a constante dentro de um método porque corre o risco de ser redesignada. Várias respostas do SO antes de mim oferecem a alternativa de atribuí-lo fora de um método - mas na classe, que é um lugar melhor para atribuí-lo.
Muito obrigado a Dorian e Phrogz por me lembrar sobre o método array (e hash) #replace, que pode "substituir o conteúdo de um array ou hash".
A noção de que o valor de um CONSTANT pode ser alterado, mas com um aviso irritante, é um dos poucos erros conceituais do Ruby - eles devem ser totalmente imutáveis ou despejar completamente a idéia constante. Do ponto de vista de um codificador, uma constante é declarativa e intencional, um sinal para outros de que "esse valor é realmente imutável uma vez declarado / atribuído".
Mas, às vezes, uma "declaração óbvia" na verdade exclui outras oportunidades úteis futuras. Por exemplo...
Não são casos de uso legítimos onde o valor de um "constante" pode realmente precisam ser alterado: por exemplo, re-loading ARGV partir de uma linha de circuito REPL-like, em seguida, executar novamente ARGV através de mais (subsequente) OptionParser.parse! chama - voila! Dá à "linha de comando args" um novo utilitário dinâmico.
O problema prático é tanto com a suposição presuntivo que "ARGV deve ser uma constante", ou no próprio método de inicialização do optparse, que rígidos códigos a atribuição de ARGV ao @default_argv instância var para posterior processamento - que array (ARGV) realmente deve ser um parâmetro, incentivando a re-análise e reutilização, quando apropriado. A parametrização adequada, com um padrão apropriado (por exemplo, ARGV) evitaria a necessidade de alterar o ARGV "constante". Apenas alguns 2 ¢ de pensamentos ...