class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
memberi saya kesalahan:
SyntaxError: kesalahan penetapan konstan dinamis
Mengapa ini dianggap sebagai konstanta dinamis? Saya hanya menetapkan string untuk itu.
class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
memberi saya kesalahan:
SyntaxError: kesalahan penetapan konstan dinamis
Mengapa ini dianggap sebagai konstanta dinamis? Saya hanya menetapkan string untuk itu.
Jawaban:
Masalah Anda adalah bahwa setiap kali Anda menjalankan metode, Anda menetapkan nilai baru ke konstanta. Ini tidak diperbolehkan, karena membuat konstan tidak konstan; meskipun isi string sama (untuk saat ini, bagaimanapun), objek string yang sebenarnya itu sendiri berbeda setiap kali metode ini dipanggil. Sebagai contoh:
def foo
p "bar".object_id
end
foo #=> 15779172
foo #=> 15779112
Mungkin jika Anda menjelaskan kasus penggunaan Anda - mengapa Anda ingin mengubah nilai konstanta dalam suatu metode - kami dapat membantu Anda dengan implementasi yang lebih baik.
Mungkin Anda lebih suka memiliki variabel instan di kelas?
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"
Jika Anda benar - benar ingin mengubah nilai konstanta dalam sebuah metode, dan konstanta Anda adalah sebuah String atau Array, Anda dapat 'menipu' dan menggunakan #replacemetode ini untuk menyebabkan objek mengambil nilai baru tanpa benar-benar mengubah objek:
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. Itu salah satu kasus di mana Ruby tidak memiliki cara sederhana.
@variable), bukan konstanta. Kalau tidak, Anda akan menugaskan kembali DBsetiap kali Anda membuat instance baru dari kelas itu.
Sequel.connectuntuk konstanta bernama DB . Bahkan, dokumentasi secara eksplisit mengatakan bahwa itu hanya rekomendasi. Itu tidak terdengar seperti kendala eksternal bagi saya.
Karena konstanta di Ruby tidak dimaksudkan untuk diubah, Ruby tidak menyarankan Anda untuk menugaskan mereka dalam bagian kode yang mungkin dieksekusi lebih dari sekali, seperti metode di dalam.
Dalam keadaan normal, Anda harus mendefinisikan konstanta di dalam kelas itu sendiri:
class MyClass
MY_CONSTANT = "foo"
end
MyClass::MY_CONSTANT #=> "foo"
Jika karena alasan tertentu Anda benar-benar perlu mendefinisikan konstanta di dalam suatu metode (mungkin untuk beberapa jenis pemrograman), Anda dapat menggunakan 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"
Lagi-lagi, const_setbukan sesuatu yang harus benar-benar Anda gunakan dalam keadaan normal. Jika Anda tidak yakin apakah Anda benar - benar ingin ditugaskan ke konstanta dengan cara ini, Anda mungkin ingin mempertimbangkan salah satu alternatif berikut:
Variabel kelas berperilaku seperti konstanta dalam banyak hal. Mereka adalah properti di kelas, dan mereka dapat diakses di subclass dari kelas yang mereka tetapkan.
Perbedaannya adalah bahwa variabel kelas dimaksudkan untuk dapat dimodifikasi, dan karenanya dapat ditugaskan ke dalam metode tanpa masalah.
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"
Atribut kelas adalah semacam "variabel instan pada kelas". Mereka berperilaku sedikit seperti variabel kelas, kecuali bahwa nilainya tidak dibagi dengan subclass.
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"
Dan hanya untuk kelengkapan yang mungkin harus saya sebutkan: jika Anda perlu menetapkan nilai yang hanya dapat ditentukan setelah kelas Anda dipakai, ada kemungkinan Anda benar-benar mencari variabel instan yang lama.
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
Di Ruby, variabel apa pun yang namanya dimulai dengan huruf kapital adalah konstan dan Anda hanya dapat menetapkan satu kali. Pilih salah satu dari alternatif ini:
class MyClass
MYCONSTANT = "blah"
def mymethod
MYCONSTANT
end
end
class MyClass
def mymethod
my_constant = "blah"
end
end
Konstanta dalam ruby tidak dapat didefinisikan di dalam metode. Lihat catatan di bagian bawah halaman ini, misalnya
Anda tidak dapat memberi nama variabel dengan huruf kapital atau Ruby akan menganggapnya sebagai konstanta dan ingin agar variabel itu tetap konstan, dalam hal ini mengubah nilainya akan menjadi kesalahan yang merupakan "kesalahan penetapan konstan yang dinamis". Dengan huruf kecil harus baik-baik saja
class MyClass
def mymethod
myconstant = "blah"
end
end
Ruby tidak suka bahwa Anda menetapkan konstanta di dalam metode karena berisiko penugasan kembali. Beberapa jawaban SO sebelum saya memberikan alternatif untuk menetapkannya di luar metode - tetapi di kelas, yang merupakan tempat yang lebih baik untuk menetapkannya.
Terima kasih banyak kepada Dorian dan Phrogz untuk mengingatkan saya tentang metode array (dan hash) #replace, yang dapat "mengganti konten array atau hash."
Gagasan bahwa nilai KONSTAN dapat diubah, tetapi dengan peringatan yang menjengkelkan, adalah salah satu dari beberapa langkah keliru konseptual Ruby - ini harus sepenuhnya tidak berubah, atau membuang ide konstan sama sekali. Dari sudut pandang seorang pembuat kode, sebuah konstanta bersifat deklaratif dan disengaja, sebuah sinyal bagi yang lain bahwa "nilai ini benar-benar tidak dapat diubah begitu dideklarasikan / ditugaskan."
Tetapi kadang-kadang "deklarasi yang jelas" sebenarnya menyita kesempatan lain yang bermanfaat di masa depan. Sebagai contoh...
Ada yang kasus penggunaan yang sah di mana nilai "konstan ini" mungkin benar-benar perlu diubah: misalnya, re-loading ARGV dari prompt loop repl-seperti, kemudian Siarang ARGV melalui lebih (berikutnya) OptionParser.parse! panggilan - voila! Memberikan "command line args" sebuah utilitas dinamis yang sama sekali baru.
Masalah praktis adalah baik dengan asumsi dugaan bahwa "ARGV harus konstan", atau dalam metode initialize optparse sendiri, yang keras-kode penugasan ARGV ke @default_argv misalnya var untuk diproses selanjutnya - bahwa array (ARGV) benar-benar harus menjadi parameter, mendorong penguraian ulang dan penggunaan kembali, jika sesuai. Parameterisasi yang tepat, dengan standar yang sesuai (katakanlah, ARGV) akan menghindari keharusan untuk mengubah ARGV "konstan". Hanya sekitar 2 ¢ - layak dipikirkan ...