class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
bana hata veriyor:
Sözdizimi Hatası: dinamik sabit atama hatası
Bu neden dinamik bir sabit olarak kabul edilir? Ben sadece ona bir dize veriyorum.
class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
bana hata veriyor:
Sözdizimi Hatası: dinamik sabit atama hatası
Bu neden dinamik bir sabit olarak kabul edilir? Ben sadece ona bir dize veriyorum.
Yanıtlar:
Sorun, yöntemi her çalıştırdığınızda sabit için yeni bir değer atamak olmasıdır. Sabit olmamasını sağladığı için buna izin verilmez; dizenin içeriği aynı olmasına rağmen (şu an için, her neyse), yöntem her çağrıldığında gerçek dize nesnesinin kendisi farklıdır. Örneğin:
def foo
p "bar".object_id
end
foo #=> 15779172
foo #=> 15779112
Belki de kullanım durumunuzu (bir yöntemdeki sabitin değerini neden değiştirmek istediğinizi) açıkladıysanız, size daha iyi bir uygulamada yardımcı olabiliriz.
Belki de sınıfta bir örnek değişkeni mi tercih edersiniz?
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"
Eğer varsa gerçekten bir yöntemde bir sabit değerini değiştirmek istiyorum, ve sürekli bir dize veya bir Array, sen 'hile' ve kullanabilirsiniz #replaceaslında nesneyi değiştirmeden yeni bir değer almak için nesneyi neden yöntemini:
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. Ruby'nin basit bir yolu olmadığı durumlardan biri.
@variablesabit değil, bir örnek değişkeni (örn. ) İstiyorsunuz . Aksi takdirde DB, söz konusu sınıfın her yeni örneğini her başlatışınızda yeniden atarsınız.
Sequel.connectDB adlı bir sabite atamanız gerektiğini söyleyen hiçbir şey görmüyorum . Aslında, belgeler açıkça bunun sadece bir tavsiye olduğunu söylüyor. Bu bana dışsal bir kısıt gibi gelmiyor.
Ruby'deki sabitlerin değiştirilmesi amaçlanmadığı için Ruby, kodları iç kodlar gibi birden fazla çalıştırılabilecek kod bölümlerine atamanızı önler.
Normal şartlar altında, sınıfın içindeki sabiti tanımlamanız gerekir:
class MyClass
MY_CONSTANT = "foo"
end
MyClass::MY_CONSTANT #=> "foo"
Herhangi bir nedenle bir yöntemin içinde bir sabit tanımlamanız gerekiyorsa (belki de bir tür metaprogramlama için), şunları kullanabilirsiniz 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"
Yine de, const_setnormal şartlar altında başvurmanız gereken bir şey değildir. Sabitlere gerçekten bu şekilde atamak isteyip istemediğinizden emin değilseniz , aşağıdaki alternatiflerden birini düşünmek isteyebilirsiniz:
Sınıf değişkenleri birçok şekilde sabit gibi davranır. Bir sınıfın özellikleridir ve tanımlandıkları sınıfın alt sınıflarında erişilebilirler.
Aradaki fark, sınıf değişkenlerinin değiştirilebilir olması ve bu nedenle sorunsuz bir şekilde iç yöntemlere atanabilmeleridir.
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"
Sınıf öznitelikleri bir çeşit "sınıftaki örnek değişkeni" dir. Değerlerinin alt sınıflarla paylaşılmaması dışında, sınıf değişkenleri gibi davranırlar.
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"
Ve sadece bütünlük için bahsetmeliyim: sadece sınıfınız başlatıldıktan sonra belirlenebilecek bir değer atamanız gerekiyorsa, aslında eski bir düz örnek değişkeni aramak için iyi bir şans var.
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
Ruby'de, adı büyük harfle başlayan herhangi bir değişken sabittir ve buna yalnızca bir kez atayabilirsiniz. Aşağıdaki alternatiflerden birini seçin:
class MyClass
MYCONSTANT = "blah"
def mymethod
MYCONSTANT
end
end
class MyClass
def mymethod
my_constant = "blah"
end
end
Yakuttaki sabitler yöntemlerin içinde tanımlanamaz. Örneğin, bu sayfanın altındaki notlara bakın
Ruby, bir yöntemin içindeki sabiti atadığınızdan hoşlanmaz çünkü yeniden atama riski vardır. Benden önce birkaç SO yanıtı, bir yöntemin dışında atama alternatifi veriyor - ancak sınıfta, atamak için daha iyi bir yer.
Dorian ve Phrogz'a, "bir dizinin veya karma'nın içeriğini değiştirebilecek" dizi (ve karma) yöntemi hakkında hatırlattığı için çok teşekkürler.
SABİT'in değerinin değiştirilebileceği, ancak can sıkıcı bir uyarıyla, Ruby'nin birkaç kavramsal yanlış adımından biridir - bunlar tamamen değişmez olmalı veya sabit fikri tamamen dökmelidir. Bir kodlayıcının bakış açısından, bir sabit bildirimsel ve kasıtlıdır, diğerine "bu değer beyan edildiğinde / atandığında gerçekten değişmezdir" sinyalidir.
Ancak bazen "açık bir deklarasyon" aslında gelecekteki diğer faydalı fırsatları da öngörür. Örneğin...
Orada vardır örneğin bir REPL benzeri istemi-döngüden yeniden yükleme ARGV, daha sonra (sonradan) OptionParser.parse aracılığıyla argv rerunning: Bir "sabitin" değeri gerçekten değiştirilmesi gerekebilir geçerli durumlar! çağrıları - voila! Tamamen yeni bir dinamik yardımcı program olan "komut satırı argümanları" verir.
Pratik problem ya "ARGV'nin sabit olması gerektiği" varsayımı ile, veya optparse kendi initialize yönteminde, hangi sert kodları sonraki işlemler için örnek var @default_argv için ARGV atama - gerçekten bu dizi (ARGV) uygun olduğunda yeniden ayrıştırma ve yeniden kullanımı teşvik eden bir parametre olmalıdır. Uygun bir varsayılan değerle (örneğin, ARGV) uygun parametrelendirme, "sabit" ARGV'yi değiştirme ihtiyacını ortadan kaldırır. Sadece bazı 2 ¢-düşünceleri değer ...