class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
daje mi błąd:
SyntaxError: błąd dynamicznego przypisania stałej
Dlaczego jest to uważane za dynamiczną stałą? Po prostu przypisuję do niego ciąg.
class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
daje mi błąd:
SyntaxError: błąd dynamicznego przypisania stałej
Dlaczego jest to uważane za dynamiczną stałą? Po prostu przypisuję do niego ciąg.
Odpowiedzi:
Twój problem polega na tym, że za każdym razem, gdy uruchamiasz metodę, przypisujesz stałą nową wartość. Jest to niedozwolone, ponieważ powoduje, że stała nie jest stała; mimo że zawartość łańcucha jest taka sama (w każdym razie w tej chwili), sam obiekt string jest inny przy każdym wywołaniu metody. Na przykład:
def foo
p "bar".object_id
end
foo #=> 15779172
foo #=> 15779112
Być może gdybyś wyjaśnił swój przypadek użycia - dlaczego chcesz zmienić wartość stałej w metodzie - moglibyśmy pomóc Ci w lepszej implementacji.
Może wolisz mieć zmienną instancji w klasie?
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"
Jeśli naprawdę chcesz zmienić wartość stałej w metodzie, a twoją stałą jest String lub Array, możesz „oszukać” i użyć #replacemetody, aby spowodować, że obiekt przybierze nową wartość bez faktycznej zmiany obiektu:
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. To jeden z tych przypadków, w których Ruby nie ma prostego sposobu.
@variable), A nie stałej. W przeciwnym razie będziesz ponownie przypisywać za DBkażdym razem, gdy utworzysz nową instancję tej klasy.
Sequel.connectdo stałej o nazwie DB . W rzeczywistości dokumentacja wyraźnie mówi, że to tylko zalecenie. Dla mnie to nie brzmi jak zewnętrzne ograniczenie.
Ponieważ stałe w Rubim nie powinny być zmieniane, Ruby odradza przypisywanie do nich części kodu, które mogą być wykonywane więcej niż jeden raz, takich jak metody wewnętrzne.
W normalnych okolicznościach należy zdefiniować stałą wewnątrz samej klasy:
class MyClass
MY_CONSTANT = "foo"
end
MyClass::MY_CONSTANT #=> "foo"
Jeśli z jakiegoś powodu naprawdę potrzebujesz zdefiniować stałą wewnątrz metody (być może dla jakiegoś typu metaprogramowania), możesz użyć 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"
Znowu jednak const_setnie jest czymś, do czego naprawdę powinieneś uciekać się w normalnych okolicznościach. Jeśli nie masz pewności, czy naprawdę chcesz przypisywać stałe w ten sposób, możesz rozważyć jedną z następujących alternatyw:
Zmienne klasowe na wiele sposobów zachowują się jak stałe. Są właściwościami klasy i są dostępne w podklasach klasy, w której zostały zdefiniowane.
Różnica polega na tym, że zmienne klas mają być modyfikowalne i dlatego można je przypisać do metod wewnętrznych bez problemu.
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"
Atrybuty klasy to rodzaj „zmiennej instancji w klasie”. Zachowują się trochę jak zmienne klasowe, z tym wyjątkiem, że ich wartości nie są współdzielone z podklasami.
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"
I dla kompletności powinienem prawdopodobnie wspomnieć: jeśli chcesz przypisać wartość, która może być określona tylko po utworzeniu instancji twojej klasy, istnieje duża szansa, że faktycznie szukasz zwykłej starej zmiennej instancji.
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
W Rubim każda zmienna, której nazwa zaczyna się od dużej litery, jest stałą i możesz ją przypisać tylko raz. Wybierz jedną z tych alternatyw:
class MyClass
MYCONSTANT = "blah"
def mymethod
MYCONSTANT
end
end
class MyClass
def mymethod
my_constant = "blah"
end
end
Stałe w ruby nie mogą być definiowane wewnątrz metod. Zobacz na przykład uwagi na dole tej strony
Nie możesz nazwać zmiennej wielkimi literami, inaczej Ruby założy, że jest to stała i będzie chciał, aby zachowała stałą wartość. W takim przypadku zmiana jej wartości byłaby błędem i „błędem dynamicznego przypisania stałej”. Z małymi literami powinno być dobrze
class MyClass
def mymethod
myconstant = "blah"
end
end
Rubiemu nie podoba się to, że przypisujesz stałą wewnątrz metody, ponieważ istnieje ryzyko ponownego przypisania. Kilka odpowiedzi SO przede mną daje alternatywę przypisywania jej poza metodą - ale w klasie, co jest lepszym miejscem do jej przypisania.
Wielkie podziękowania dla Doriana i Phrogza za przypomnienie mi o metodzie tablicowej (i haszującej) #replace, która może „zastąpić zawartość tablicy lub skrótu”.
Pogląd, że wartość STAŁA można zmienić, ale z irytującym ostrzeżeniem, jest jednym z niewielu błędnych kroków koncepcyjnych Rubiego - powinny one albo być w pełni niezmienne, albo całkowicie odrzucić stałą ideę. Z punktu widzenia programisty stała jest deklaratywna i zamierzona, jest sygnałem dla innych, że „ta wartość jest naprawdę niezmienna po zadeklarowaniu / przypisaniu”.
Czasami jednak „oczywista deklaracja” faktycznie wyklucza inne, przydatne w przyszłości możliwości. Na przykład...
Tam są przypadki legalnego wykorzystania gdzie wartość danej „Constant za” może naprawdę trzeba być zmieniony, na przykład: ponowne ładowanie ARGV z REPL podobny szybkiej pętli, a następnie ponowne uruchomienie ARGV thru więcej (późniejszej) OptionParser.parse! rozmowy - voila! Daje „argumentom wiersza poleceń” zupełnie nowe dynamiczne narzędzie.
Praktyczny problem jest albo z przypuszczalnego założeniu, że „ARGV musi być ciągle”, lub w oddzielnym metody initialize optparse, która twardych koduje przyporządkowanie ARGV do @default_argv przykład var do dalszej obróbki - że tablica (ARGV) rzeczywiście powinien być parametrem zachęcającym do ponownej analizy i ponownego wykorzystania, w stosownych przypadkach. Właściwa parametryzacja z odpowiednią wartością domyślną (powiedzmy ARGV) pozwoliłaby uniknąć konieczności zmiany „stałej” wartości ARGV. Zaledwie 2 grosze myśli ...