วันนี้ผมจะมาพูดถึง 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