ทำไม Ruby Setters จึงต้องการการระบุ self. ภายในคลาส?

ในโลกของภาษาโปรแกรมมิง ภาษาต่าง ๆ มีไวยากรณ์และกฎเฉพาะของตัวเองที่กำหนดว่าโค้ดถูกสร้างและดำเนินการอย่างไร Ruby ซึ่งเป็นภาษาโปรแกรมมิงแบบไดนามิกและเชิงวัตถุ มีลักษณะเฉพาะที่ไม่เหมือนใครเมื่อพูดถึงวิธีการ setter โดยเฉพาะอย่างยิ่ง ผู้ตั้งค่า Ruby—ไม่ว่าจะถูกสร้างขึ้นโดยการใช้ attr_accessor หรือถูกกำหนดขึ้นเอง จะต้องการการระบุ self. เมื่อถูกเข้าถึงจากภายในคลาสเอง บทความนี้จะเจาะลึกถึงเหตุผลเบื้องหลังข้อกำหนดนี้และสำรวจผลกระทบในการเขียนโปรแกรม Ruby

ปัญหา: ความคลุมเครือของวิธีการ Setter

เมื่อคุณกำลังเขียนคลาส Ruby คุณอาจสังเกตเห็นว่าในขณะที่วิธีการของอินสแตนซ์สามารถถูกเรียกโดยไม่ต้องการการระบุ แต่ setter กลับเสนอกรณีที่แตกต่าง ลองมาทำความเข้าใจกับจุดสำคัญเกี่ยวกับการระบุวิธีการ:

  • ภาษาโปรแกรมมิงบางภาษา เช่น C# และ Java ไม่ต้องการ this หรือ self สำหรับการเรียกวิธีการ ซึ่งทำให้โครงสร้างทางไวยากรณ์ของพวกเขาง่ายขึ้นในหลายกรณี
  • ภาษาอื่น ๆ รวมถึง Perl และ JavaScript จำเป็นต้องใช้ self หรือ this สำหรับวิธีการทั้งหมดอย่างสม่ำเสมอ
  • Ruby อยู่ในระหว่าง—เพียงแต่วิธีการ setter ของมันเท่านั้นที่บังคับใช้การระบุ self. ซึ่งนำไปสู่ความสับสนที่อาจเกิดขึ้น

ตัวอย่างใน Ruby

เพื่อเน้นย้ำพฤติกรรมนี้ ให้พิจารณาคลาส Ruby ต่อไปนี้:

class A
  def qwerty; @q; end                   # manual getter
  def qwerty=(value); @q = value; end   # manual setter
  def asdf; self.qwerty = 4; end        # "self." is necessary
  def xxx; asdf; end                    # no need for "self."
  def dump; puts "qwerty = #{qwerty}"; end
end

a = A.new
a.xxx
a.dump

หากคุณลบ self ออกจาก self.qwerty = 4 ในวิธีการ asdf Ruby จะเกิดข้อผิดพลาด ซึ่งบ่งบอกว่าไม่สามารถระบุวิธีการ setter ที่ต้องการได้ ซึ่งเน้นย้ำถึงความจำเป็นในการระบุ self. สำหรับวิธีการ setter ที่อาจเกิดความคลุมเครือ

เข้าใจความต้องการ

ทำไมต้อง self.?

ข้อกำหนดของ self. ใน Ruby หมุนรอบการจัดการความคลุมเครือ เมื่อคุณเขียนคำแถลงเช่น qwerty = 4 Ruby จำเป็นต้องแยกความแตกต่างระหว่างสองความเป็นไปได้:

  1. การเรียกวิธีการ: อาจกำลังพยายามเรียกวิธีการ setter ที่ชื่อ qwerty=
  2. การกำหนดตัวแปรท้องถิ่น: อาจกำลังประกาศตัวแปรท้องถิ่นใหม่ที่ชื่อ qwerty

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

การเปรียบเทียบกับ C#

ในทางตรงกันข้าม C# ใช้โมเดลที่อนุญาตให้เรียกใช้ setter โดยไม่ต้องการการระบุ this ตัวอย่างเช่น:

public class A {
  public int qwerty { get; set; }
  public void asdf() { qwerty = 4; } // C# setters work without "this."
}

การออกแบบทางไวยากรณ์นี้ทำให้โค้ดง่ายขึ้น แต่ก็มีความซับซ้อนในตัวเอง ใน C# ชื่อของตัวแปรและวิธีการจะถูกเข้าใจตามบริบทโดยคอมไพล์เลอร์ จึงช่วยลดความคลุมเครือบางประการที่มีอยู่ใน Ruby

เมื่อใดที่ต้องการ self. ใน Ruby?

นอกจากวิธีการ setter แล้ว ยังมีกรณีอื่น ๆ ใน Ruby ที่จำเป็นต้องมี self. เพื่อแยกความแตกต่างระหว่างการเรียกวิธีการและการกำหนดตัวแปร:

  • เมื่อตัวแปรท้องถิ่นมีชื่อเดียวกันกับวิธีการ: หากคุณมีทั้งวิธีการและตัวแปรที่ชื่อ foo การเรียก foo จะทำให้เรียกวิธีการ ขณะที่ foo = value จะทำการกำหนดตัวแปรท้องถิ่น
  • เมื่อต้องการทำให้ชัดเจน: การใช้ self. ยังสามารถทำหน้าที่เพื่อทำให้ชัดเจนแก่ผู้อ่านว่าคุณตั้งใจจะเรียกวิธีการแทนที่จะกำหนดตัวแปรท้องถิ่น

สรุป

ความจำเป็นในการระบุ self. ใน Ruby setters นำมาซึ่งการอภิปรายที่น่าสนใจเกี่ยวกับการออกแบบภาษาโปรแกรมมิงและการแก้ปัญหาความคลุมเครือ การเข้าใจคุณลักษณะเหล่านี้ไม่เพียงแต่ช่วยให้คุณเขียนโค้ด Ruby ได้ดีขึ้น แต่ยังช่วยให้คุณเข้าใจลึกซึ้งยิ่งขึ้นเกี่ยวกับวิธีการที่ภาษาต่าง ๆ เข้าหาโครงสร้างที่คล้ายกัน ในขณะที่มันอาจทำให้คุณต้องพิมพ์อักขระเพิ่มเติม แต่มันทำให้เกิดความชัดเจนและมีเจตนาในการเรียกวิธีการ ซึ่งเป็นหลักการพื้นฐานของปรัชญาการออกแบบของ Ruby ดังนั้น ครั้งถัดไปที่คุณอยู่ในระหว่างการเขียนโค้ด Ruby ให้จำไว้ว่า self. ไม่ใช่เพียงข้อกำหนด—มันเป็นกุญแจสำคัญในการหลีกเลี่ยงความคลุมเครือและเสริมสร้างความสามารถในการอ่านโค้ด