วันนี้พูดถึง self เขียน Ruby มาสักพักน่าจะ internalize แนวคิด self แล้ว อ่าน/เขียนโปรแกรม self อยู่หลังหัวเสมอ
แต่นักพัฒนาที่ใหม่ self น่ฮือสับ เปลี่ยนแปลงตลอดแต่ไม่ explicit ในโค้ด คาดว่าแค่รู้
ปัญหาเยอะของ beginners มาจากไม่เข้าใจ self เคย "หาย" instance variable หรือปวดหัวว่า data ไหน visible ให้ mixin เพราะไม่เข้าใจ self ใน context นั้น
โพสต์นี้ดู self ใน everyday situations หลากหลาย
self คืออะไร?
อาจได้ยินว่า everything in Ruby is an object ถ้าเป็นจริง ทุกโค้ดที่เขียน "เป็นของ" object ใด object หนึ่ง
self คือ special variable ชี้ไป object ที่ "เป็นเจ้าของ" currently executing code Ruby ใช้ self ทุกที่:
- Instance variables:
@myvar - Method และ constant lookup
- ตอน define methods, classes, modules
ทฤษฎี self ชัดเจน แต่ปฏิบัติ tricky situations วิ่งออกมาได้ง่าย นั่นคือเหตุผลที่เขียนโพสต์นี้
ตัวอย่าง self
ผ่านหลายตัวอย่าง ถ้าแรก basic เกินไป อ่านต่อ ได้ advanced ขึ้นเรื่อยๆ
ภายใน Instance Method
โค้ดด้านล่าง reflect เป็น instance method เป็นของ object ที่สร้างผ่าน Ghost.new ดังนั้น self ชี้ object นั้น
class Ghost
def reflect
self
end
end
g = Ghost.new
g.reflect == g # => true
ภายใน Class Method
ตัวอย่าง reflect เป็น class method ของ Ghost Class methods คลาสตัวเอง "เป็นเจ้าของ" method self ชี้ class
class Ghost
def self.reflect
self
end
end
Ghost.reflect == Ghost # => true
เหมือนกันกับ "class" methods ใน modules:
module Ghost
def self.reflect
self
end
end
Ghost.reflect == Ghost # => true
จำไว้: classes และ modules ถูก treat เป็น objects ใน Ruby พฤติกรรมนี้ไม่ต่างจาก instance method behavior ตัวแรกมาก
ภายใน Class หรือ Module Definition
Feature ทำ Ruby เหมาะ frameworks เช่น Rails: execute arbitrary code ภายใน class/module definitions ได้ เวลาวางโค้ดใน class/module definition มันรันเหมือน Ruby code ปกติ ความต่างคือค่า self
เห็นได้ self ชี้ class หรือ module ที่กำลัง defined:
class Ghost
self == Ghost # => true
end
module Mummy
self == Mummy # => true
end
ภายใน Mixin Methods
Mixed-in methods behave เหมือน "normal" instance/class methods เกี่ยวกับ self ทำ sense ไม่งั้น mixin interact กับ class ที่ mix เข้าไม่ได้
Instance methods
แม้ reflect defined ใน module self เป็น instance ของ class ที่ mix เข้า
module Reflection
def reflect
self
end
end
class Ghost
include Reflection
end
g = Ghost.new
g.reflect == g # => true
Class methods
เวลา extend class mix in class methods self behave เหมือน normal class methods
module Reflection
def reflect
self
end
end
class Ghost
extend Reflection
end
Ghost.reflect == Ghost # => true
ภายใน Metaclass
น่าจะเคยเหย shortcut ยอดนิยม define class methods หลายๆ ตัว:
class Ghost
class << self
def method1
end
def method2
end
end
end
class << foo syntax น่าสนใจ เข้าถึง metaclass ของ object - เรียกว่า "singleton class" หรือ "eigenclass" วางแผน cover metaclasses ลึกในโพสต์หน้า ตอนนี้แค่รู้ว่า metaclass ที่ Ruby เก็บ methods unique to specific object
เข้าถึง self จากใน class << foo block ได้ metaclass:
class << "test"
puts self.inspect
end
# => #>
นอก Class ใดๆ
รันโค้ดนอก class ใดๆ Ruby ยังให้ self ชี้ "main" ซึ่งเป็น instance ของ Object:
puts self.inspect # => main