class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
ให้ฉันข้อผิดพลาด:
SyntaxError: ข้อผิดพลาดการกำหนดค่าคงที่แบบไดนามิก
เหตุใดจึงถือว่าค่าคงที่แบบไดนามิกนี้ ฉันแค่กำหนดสตริงให้
class MyClass
def mymethod
MYCONSTANT = "blah"
end
end
ให้ฉันข้อผิดพลาด:
SyntaxError: ข้อผิดพลาดการกำหนดค่าคงที่แบบไดนามิก
เหตุใดจึงถือว่าค่าคงที่แบบไดนามิกนี้ ฉันแค่กำหนดสตริงให้
คำตอบ:
ปัญหาของคุณคือทุกครั้งที่คุณเรียกใช้เมธอดที่คุณกำหนดค่าใหม่ให้กับค่าคงที่ สิ่งนี้ไม่ได้รับอนุญาตเนื่องจากมันทำให้ค่าคงที่แบบไม่คงที่ แม้ว่าเนื้อหาของสตริงจะเหมือนกัน (ในขณะใดก็ตาม) วัตถุสตริงที่แท้จริงนั้นแตกต่างกันในแต่ละครั้งที่เรียกใช้เมธอด ตัวอย่างเช่น:
def foo
p "bar".object_id
end
foo #=> 15779172
foo #=> 15779112
บางทีถ้าคุณอธิบายกรณีการใช้งานของคุณ - ทำไมคุณต้องการเปลี่ยนค่าของค่าคงที่ในวิธีการ - เราสามารถช่วยคุณในการนำไปใช้ที่ดีขึ้น
บางทีคุณอยากจะมีตัวแปรอินสแตนซ์ในชั้นเรียนหรือไม่
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"
หากคุณจริงๆต้องการที่จะเปลี่ยนค่าของคงที่ในวิธีการและคุณคงเป็นสตริงหรืออาร์เรย์คุณสามารถ 'โกง' และใช้#replace
วิธีการที่จะทำให้วัตถุที่จะใช้ในค่าใหม่โดยไม่ต้องเปลี่ยนวัตถุ:
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 ไม่มีวิธีการง่ายๆ
@variable
) ไม่ใช่ค่าคงที่ มิฉะนั้นคุณจะกำหนดใหม่DB
ทุกครั้งที่คุณสร้างอินสแตนซ์ใหม่ของคลาสนั้น
Sequel.connect
ให้กับ DB ที่คงที่ . ในความเป็นจริงเอกสารอธิบายอย่างชัดเจนว่าเป็นเพียงคำแนะนำ ไม่ได้ฟังเหมือนข้อ จำกัด ภายนอกสำหรับฉัน
เนื่องจากค่าคงที่ใน Ruby ไม่ได้หมายถึงการเปลี่ยนแปลง Ruby จึงไม่สนับสนุนให้คุณกำหนดในส่วนของรหัสที่อาจถูกเรียกใช้มากกว่าหนึ่งครั้งเช่นวิธีการภายใน
ภายใต้สถานการณ์ปกติคุณควรกำหนดค่าคงที่ภายในคลาสเอง:
class MyClass
MY_CONSTANT = "foo"
end
MyClass::MY_CONSTANT #=> "foo"
หากด้วยเหตุผลบางอย่างถึงแม้ว่าคุณจำเป็นต้องกำหนดค่าคงที่ภายในเมธอด (บางทีสำหรับเมตาโปรแกรมบางประเภท) คุณสามารถใช้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"
อีกครั้งแม้ว่าconst_set
ไม่ใช่สิ่งที่คุณควรจะต้องหันไปใช้ภายใต้สถานการณ์ปกติ หากคุณไม่แน่ใจว่าคุณต้องการกำหนดให้กับค่าคงที่ด้วยวิธีนี้จริง ๆหรือไม่คุณอาจต้องพิจารณาทางเลือกใดทางเลือกหนึ่งต่อไปนี้:
ตัวแปรคลาสมีลักษณะเหมือนค่าคงที่หลายวิธี พวกเขาเป็นคุณสมบัติในชั้นเรียนและพวกเขาสามารถเข้าถึงได้ในคลาสย่อยของชั้นเรียนที่พวกเขากำหนดไว้
ความแตกต่างคือตัวแปรคลาสนั้นสามารถแก้ไขได้และสามารถกำหนดให้กับวิธีการภายในได้โดยไม่มีปัญหา
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"
แอตทริบิวต์ class เป็นประเภท "ตัวแปรอินสแตนซ์ในคลาส" พวกเขาทำตัวเหมือนตัวแปรคลาสยกเว้นว่าค่าของพวกเขาจะไม่ถูกแชร์กับคลาสย่อย
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"
และเพื่อความสมบูรณ์ฉันน่าจะพูดถึง: ถ้าคุณต้องการกำหนดค่าที่สามารถกำหนดได้หลังจากที่คลาสของคุณได้รับอินสแตนซ์แล้วมีโอกาสดีที่คุณอาจกำลังมองหาตัวแปรอินสแตนซ์เก่าแบบธรรมดา
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 ตัวแปรใด ๆ ที่ชื่อขึ้นต้นด้วยตัวพิมพ์ใหญ่เป็นค่าคงที่และคุณสามารถกำหนดได้เพียงครั้งเดียวเท่านั้น เลือกหนึ่งในตัวเลือกเหล่านี้:
class MyClass
MYCONSTANT = "blah"
def mymethod
MYCONSTANT
end
end
class MyClass
def mymethod
my_constant = "blah"
end
end
ค่าคงที่ในทับทิมไม่สามารถกำหนดได้ภายในวิธีการ ดูหมายเหตุที่ด้านล่างของหน้านี้ตัวอย่างเช่น
คุณไม่สามารถตั้งชื่อตัวแปรด้วยตัวอักษรพิมพ์ใหญ่หรือ Ruby จะถือว่าค่าคงที่และต้องการให้ค่าคงที่ซึ่งในกรณีนี้การเปลี่ยนค่าจะเป็นข้อผิดพลาด "ข้อผิดพลาดการกำหนดค่าคงที่แบบไดนามิก" ด้วยตัวพิมพ์เล็กควรจะดี
class MyClass
def mymethod
myconstant = "blah"
end
end
ทับทิมไม่ชอบที่คุณกำลังกำหนดค่าคงที่ภายในของวิธีการเพราะมันเสี่ยงต่อการกำหนดใหม่ คำตอบ SO จำนวนมากก่อนที่ฉันจะให้ทางเลือกในการมอบหมายนอกวิธีการ - แต่ในชั้นเรียนซึ่งเป็นสถานที่ที่ดีกว่าในการมอบหมาย
ขอบคุณ Dorian และ Phrogz สำหรับเตือนฉันเกี่ยวกับวิธีอาร์เรย์ (และแฮช) #replace ซึ่งสามารถ "แทนที่เนื้อหาของอาร์เรย์หรือแฮช"
ความคิดที่ว่าค่าคงที่ของค่าคงที่สามารถเปลี่ยนแปลงได้ แต่ด้วยการเตือนที่น่ารำคาญเป็นหนึ่งในขั้นตอนการคิดผิดพลาดที่ไม่กี่ขั้นตอนของ Ruby - สิ่งเหล่านี้ควรจะไม่เปลี่ยนแปลงอย่างสมบูรณ์หรือทิ้งความคิดคงที่ทั้งหมด จากมุมมองของโคเดอร์นค่าคงที่คือการประกาศและจงใจสัญญาณที่บ่งบอกว่า "ค่านี้ไม่สามารถเปลี่ยนแปลงได้จริงเมื่อประกาศ / กำหนดแล้ว"
แต่บางครั้ง "ประกาศชัดเจน" จริง ๆ แล้วรอโอกาสอื่น ๆ ที่เป็นประโยชน์ในอนาคต ตัวอย่างเช่น...
มีอยู่เช่นเรื่องการโหลด ARGV จาก REPL เหมือนพรอมต์วงแล้ว rerunning ARGV ผ่านมากขึ้น (ต่อมา) OptionParser.parse: กรณีการใช้งานถูกต้องตามกฎหมายที่ "คงที่" ค่าอาจจำเป็นจริงๆที่จะเปลี่ยนแปลง! โทร - voila! ให้ "บรรทัดคำสั่ง args" ยูทิลิตี้แบบไดนามิกใหม่ทั้งหมด
ปัญหาที่เกิดขึ้นจริงนั้นเป็นไปได้ด้วยสมมติฐานที่สันนิษฐานว่า "ARGV ต้องเป็นค่าคงที่" หรือในวิธีการเริ่มต้นของ optparse เองซึ่งรหัสยาก ๆ ที่กำหนด ARGV ให้กับอินสแตนซ์ var @default_argv สำหรับการประมวลผลในภายหลัง - ARGV จริง ๆ ควรเป็นพารามิเตอร์กระตุ้นการแยกวิเคราะห์และการใช้ซ้ำตามความเหมาะสม การกำหนดพารามิเตอร์ที่เหมาะสมด้วยค่าเริ่มต้นที่เหมาะสม (พูด ARGV) จะหลีกเลี่ยงความต้องการที่จะเปลี่ยน ARGV "คงที่" เพียงแค่ 2 worth - คิดมาก ...