Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

ทำความเข้าใจเกี่ยวกับการปรับแต่งทับทิมและขอบเขตคำศัพท์

หากคุณไม่เคยใช้การปรับแต่งมาก่อน คุณอาจจะแปลกใจ คุณอาจเคยได้ยินว่ามีการแนะนำการปรับแต่งเพื่อแทนที่การปะลิง ดังนั้นคุณอาจคาดหวังว่าคุณจะสามารถใช้งานบางอย่างเช่น hours . ของ ActiveSupport วิธีการ:

module TimeExtension
  refine Fixnum do
    def hours
      self * 60
    end
  end
end

class MyFramework
  using TimeExtension
end

class MyApp < MyFramework
  def index
    1.hours
  end
end

MyApp.new.index # undefined method `hours' for 1:Fixnum (NoMethodError)

หากคุณรันโค้ดด้านบน คุณจะพบว่ามันไม่ได้ผล แล้วให้อะไร?

เช่นเดียวกับแนวคิดที่ยอดเยี่ยมอื่นๆ มากมาย แนวคิดดั้งเดิมของการปรับแต่งต้องได้รับการปรับแต่งเพื่อให้ทำงานกับความเป็นจริงที่เยือกเย็นได้

พฤติกรรมที่น่าประหลาดใจในโค้ดที่เราดูด้านบนนี้เกิดจากการปรับแต่งอย่างใดอย่างหนึ่งเหล่านี้ โดยเฉพาะอย่างยิ่ง กฎที่ระบุว่าการปรับแต่งมีการกำหนดขอบเขตคำศัพท์

การกำหนดขอบเขตคำศัพท์คืออะไร

เมื่อเราพูดว่าบางสิ่งเป็นศัพท์เฉพาะ นั่นหมายความว่าเกี่ยวข้องกับข้อความ — โค้ดบนหน้าจอซึ่งต่างจากความหมายของโค้ดนั้น

หากมีการกำหนดขอบเขตคำศัพท์สองบรรทัด ก็หมายความว่าเกิดขึ้นภายในบล็อกโค้ดเดียวกัน โดยไม่คำนึงว่าบล็อกโค้ดนั้นจะประเมินอะไร

ดูตัวอย่างง่ายกว่าพูดมาก:

class B
  # x and y share the same lexical scope
  x = 1
  y = 1
end

class B
  # z has a different lexical scope from x and y, even though it's in the same class. 
  z = 3
end

การปรับแต่งมีการกำหนดขอบเขตคำศัพท์

เมื่อเราใช้การปรับแต่งด้วยคำสำคัญที่ใช้ การปรับแต่งจะปรากฏเฉพาะภายในขอบเขตคำศัพท์เท่านั้น

นี่คือตัวอย่างที่ฉันหมายถึง:

module TimeExtension
  refine Fixnum do
    def hours
      self * 60
    end
  end
end

class MyApp
  using TimeExtension
  def index
    1.hours
  end
end

class MyApp
  def show
    2.hours
  end
end

MyApp.new.show # undefined method `hour' for 1:Fixnum (NoMethodError)

ทั้งที่ทั้ง index และ show เมธอดเป็นส่วนหนึ่งของคลาสเดียวกัน เฉพาะ index เมธอดมีการเข้าถึงการปรับแต่ง เพราะมีเพียงการใช้ขอบเขตคำศัพท์ร่วมกับ using คำสั่ง

นี่อาจดูแปลกๆ นิดหน่อย เพราะเกือบทุกอย่างใน Ruby นั้นมีการกำหนดขอบเขตแบบไดนามิก เมื่อคุณเพิ่มเมธอดในคลาส เมธอดจะอยู่ที่นั่นเมื่อคุณออกจากนิยามคลาส แต่นั่นไม่ใช่วิธีการกลั่นกรอง

นี่เป็นผลที่ตามมาจำนวนหนึ่งที่อาจไม่ชัดเจนในตอนแรก

คุณไม่สามารถเรียกวิธีการปรับแต่งแบบไดนามิกได้

เนื่องจาก send ไม่ได้กำหนดเมธอดภายในบล็อคโค้ดเดียวกันกับที่ใช้คำสั่งของคุณ แต่จะไม่เห็นการปรับแต่ง

วิธีนี้ใช้ไม่ได้ผล:

class MyApp
  using TimeExtension
  def index
    1.send(:hours)
  end
end

คุณไม่สามารถสืบค้นการมีอยู่ของวิธีการปรับแต่งได้

respond_to? เมธอดไม่ได้อยู่ในบล็อคโค้ดเดียวกัน ดังนั้นจึงใช้งานไม่ได้ด้วยเหตุผลเดียวกันกับที่send วิธีการไม่ได้

class MyApp
  using TimeExtension
  def index
    1.respond_to?(:hours)
  end
end

บทสรุป

ฉันหวังว่าสิ่งนี้จะช่วยขจัดความสับสนบางอย่างที่ฉันเห็นผู้คนมีเกี่ยวกับการปรับแต่ง เป็นคุณสมบัติที่มีประโยชน์อย่างแน่นอนของ Ruby แต่ถ้าคุณไม่เคยใช้มาก่อน มันอาจจะยุ่งยากเล็กน้อย