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

เข้าใจ 'ตัวเอง' ใน Ruby

วันนี้ผมจะมาพูดถึง self . หากคุณเคยเขียนโปรแกรม Ruby มาสักระยะแล้ว คุณก็น่าจะเข้าใจแนวคิดของself . เมื่อใดก็ตามที่คุณอ่านหรือเขียนโปรแกรม self อยู่ในจิตใจของคุณ

แต่สำหรับ Rubyists ที่ไม่ค่อยมีประสบการณ์ self สามารถทำให้งงงัน มีการเปลี่ยนแปลงอยู่เสมอ แต่ไม่เคยแสดงอย่างชัดเจนในโค้ด คุณแค่คาดหวังที่จะรู้

ปัญหามากมายที่ผู้เริ่มเรียนพบเจอเกิดจากการไม่เข้าใจself . หากคุณเคย "สูญเสีย" ตัวแปรอินสแตนซ์หรือสับสนกับข้อมูลที่มิกซ์อินมองเห็น นั่นเป็นเพราะคุณไม่เข้าใจself ในบริบทนั้นๆ

ในบทความนี้เราจะมาดูที่ self ในหลากหลายสถานการณ์ในแต่ละวัน

selfคืออะไร ?

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

self เป็นตัวแปรพิเศษที่ชี้ไปที่อ็อบเจ็กต์ที่ "เป็นเจ้าของ" โค้ดที่กำลังรันอยู่ Ruby ใช้ self ทุกที่:

  • สำหรับตัวแปรเช่น @myvar
  • สำหรับวิธีการและการค้นหาอย่างต่อเนื่อง
  • เมื่อกำหนดวิธีการ คลาสและโมดูล

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

ตัวอย่าง self

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

ภายในเมธอดของอินสแตนซ์

ในโค้ดด้านล่าง reflect เป็นวิธีอินสแตนซ์ มันเป็นของวัตถุที่เราสร้างผ่าน Ghost.new . ดังนั้น self ชี้ไปที่วัตถุนั้น

class Ghost
  def reflect
    self
  end
end

g = Ghost.new
g.reflect == g # => true

ภายในเมธอดของคลาส

สำหรับตัวอย่างนี้ reflect เป็นวิธีการเรียนของ Ghost . ด้วยเมธอดของคลาส คลาสเองจะ "เป็นเจ้าของ" เมธอด self ชี้ไปที่ชั้นเรียน

class Ghost
  def self.reflect
    self
  end
end

Ghost.reflect == Ghost # => true

มันทำงานเหมือนกันกับวิธีการ "คลาส" ภายในโมดูล ตัวอย่างเช่น:

module Ghost
  def self.reflect
    self
  end
end 
Ghost.reflect == Ghost # => true

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

ภายในคำจำกัดความของคลาสหรือโมดูล

คุณลักษณะหนึ่งของ Ruby ที่ทำให้เหมาะสำหรับเฟรมเวิร์กอย่าง Rails คือคุณสามารถรันโค้ดโดยอำเภอใจภายในคำจำกัดความของคลาสและโมดูล เมื่อคุณใส่โค้ดในนิยามคลาส/โมดูล มันจะทำงานเหมือนกับโค้ด Ruby อื่นๆ ความแตกต่างเพียงอย่างเดียวคือคุณค่าของ self .

ดังที่คุณเห็นด้านล่าง self ชี้ไปที่คลาสหรือโมดูลที่อยู่ในขั้นตอนการกำหนด

class Ghost
  self == Ghost # => true
end 

module Mummy
  self == Mummy # => true
end 

วิธีมิกซ์อินภายใน

เมธอดแบบผสมจะทำงานเหมือนกับอินสแตนซ์ "ปกติ" หรือเมธอดของคลาส เมื่อพูดถึง self . สิ่งนี้สมเหตุสมผล มิเช่นนั้นมิกซ์อินจะไม่สามารถโต้ตอบกับคลาสที่คุณผสมมันได้

วิธีอินสแตนซ์

แม้ว่า reflect วิธีการถูกกำหนดในโมดูล self เป็นตัวอย่างของคลาสที่ผสมเข้า

module Reflection
  def reflect
    self
  end
end 

class Ghost
  include Reflection
end

g = Ghost.new
g.reflect == g # => true

วิธีการของคลาส

เมื่อเรา extend คลาสที่จะผสมในเมธอดของคลาส self ทำงานเหมือนกับที่ทำในวิธีการเรียนปกติ

module Reflection
  def reflect
    self
  end
end 

class Ghost
  extend Reflection
end

Ghost.reflect == Ghost # => true

ภายใน metaclass

เป็นไปได้มากที่คุณจะได้เห็นช็อตคัทยอดนิยมสำหรับกำหนดวิธีการเรียนจำนวนมากในคราวเดียว

class Ghost
  class << self 
    def method1
    end

    def method2
    end
  end
end

class << foo ไวยากรณ์น่าสนใจทีเดียว ช่วยให้คุณเข้าถึง metaclass ของวัตถุ - ซึ่งเรียกอีกอย่างว่า "singleton class" หรือ "eigenclass" ฉันวางแผนที่จะครอบคลุม metaclasses อย่างลึกซึ้งยิ่งขึ้นในโพสต์ในอนาคต แต่สำหรับตอนนี้ คุณเพียงแค่ต้องรู้ว่า metaclass เป็นที่ที่ Ruby จัดเก็บเมธอดที่มีลักษณะเฉพาะสำหรับอ็อบเจกต์เฉพาะ

หากคุณเข้าถึง self จากภายใน class << foo บล็อก คุณได้รับ metaclass

class << "test"
  puts self.inspect
end

# => #<Class:#<String:0x007f8de283bd88>

นอกชั้นเรียน

หากคุณกำลังเรียกใช้โค้ดนอกคลาสใดๆ Ruby ยังคงให้ self . มันชี้ไปที่ "หลัก" ซึ่งเป็นตัวอย่างของ Object :

puts self.inspect # => main