2011-07-15 9 views
103
class MyClass 
    def mymethod 
    MYCONSTANT = "blah" 
    end 
end 

me da el error:asignación dinámica constante

SyntaxError: dynamic constant assignment error

Por qué es esto considerado una constante dinámica? Solo le estoy asignando una cadena.

+25

¿Dynamic Constant es algo así como Dry Water? :) – fl00r

+30

No dice que la constante es dinámica. Dice que la tarea es dinámica. – sepp2k

Respuesta

99

Su problema es que cada vez que ejecuta el método está asignando un nuevo valor a la constante. Esto no está permitido, ya que hace que la constante no sea constante; aunque el contenido de la cadena es el mismo (por el momento, de todos modos), la cadena real objeto sí mismo es diferente cada vez que se llama al método. Por ejemplo:

def foo 
    p "bar".object_id 
end 

foo #=> 15779172 
foo #=> 15779112 

Tal vez si usted explicó su caso, ¿por qué el uso que desea cambiar el valor de una constante en un método que usted podría ayudar con una mejor aplicación.

Quizás prefiera tener una variable de instancia en la clase?

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" 

Si realmente desea cambiar el valor de una constante en un método, y su constante es una cadena o una matriz, se puede 'engañar' y utilizar el método #replace a hacer que el objeto de tomar en un nuevo valor sin cambiar realmente el 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" 
+18

El OP nunca dijo que quería cambiar el valor de la constante sino que solo quería asignar un valor. El caso de uso frecuente que conduce a este error de Ruby es cuando construyes el valor en un método de otros activos en tiempo de ejecución (variables, argumentos de línea de comandos, ENV), típicamente en un constructor, p. 'def initialize (db, user, password) DB = Sequel.connect (" postgres: // # {user}: # {password} @ localhost/# {db} "end'. Es uno de esos casos en que Ruby no tiene una manera simple. –

+1

@ArnaudMeuret Para ese caso, desea una variable de instancia (por ejemplo, '@ variable'), no una constante. De lo contrario, volverías a asignar 'DB' cada vez que instanciaras una nueva instancia de esa clase. – Ajedi32

+2

@ Ajedi32 Esta situación generalmente se debe a restricciones externas, no a elecciones de diseño, como mi ejemplo con Sequel. Mi punto es que la asignación de un valor a una constante está permitida por Ruby en ciertos ámbitos y no en otros. Solía ​​depender del desarrollador elegir con prudencia cuándo realizar la tarea. Ruby cambió en esto. No para todos es bueno. –

19

en Ruby, cualquier variable cuyo nombre comienza con una letra mayúscula es una constante y sólo se puede asignar a la misma vez. Elija una de estas alternativas:

class MyClass 
    MYCONSTANT = "blah" 

    def mymethod 
    MYCONSTANT 
    end 
end 

class MyClass 
    def mymethod 
    my_constant = "blah" 
    end 
end 
56

Debido a las constantes en Ruby no están destinados a ser cambiado, Ruby le desanima a las asignaciones a ellos en partes de código que podría se ejecutan más de una vez, tales como los métodos de su interior.

En circunstancias normales, debería definir la constante dentro de la propia clase:

class MyClass 
    MY_CONSTANT = "foo" 
end 

MyClass::MY_CONSTANT #=> "foo" 

Si por alguna razón, aunque realmente es necesario definir una constante dentro de un método (tal vez por algún tipo de metaprogramming), puede utilizar 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" 

Otra vez sin embargo, const_set no es algo que realmente debería tener que recurrir a bajo circunstancias normales. Si no está seguro de si realmente quiere estar asignando a las constantes de esta manera, es posible que desee considerar una de las siguientes alternativas:

Las variables de clase

Las variables de clase se comportan como constantes en muchas maneras. Son propiedades de una clase, y están accesibles en subclases de la clase en la que están definidas.

La diferencia es que las variables de clase están destinadas a ser modificables, y por lo tanto se pueden asignar a métodos internos sin problemas.atribuye

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" 

Clase

Los atributos de clase son una especie de "variable de instancia de una clase". Se comportan un poco como las variables de clase, excepto que sus valores no se comparten con las subclases.

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" 

Las variables de instancia

Y simplemente para la corrección probablemente debería mencionar: si tiene que asignar un valor que sólo puede ser determinado después de que su clase ha creado una instancia, hay una buena probabilidad de que en realidad podría estar buscando para una simple variable de instancia antigua.

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 
+0

Esta es la respuesta más clara. – Snowcrash

+0

'const_set' es la respuesta correcta. – robbie613

0

No se puede nombrar una variable con letras mayúsculas o Ruby se ASUME es una constante y querrá que lo mantenga constante de valor, en el que el cambio caso se trata de valor sería un error "un error de asignación dinámica constante ". Con minúscula debería estar bien

class MyClass 
    def mymethod 
    myconstant = "blah" 
    end 
end 
Cuestiones relacionadas