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 - คิดมาก ...