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

เชี่ยวชาญขอบเขตตัวแปรและการผูกออบเจ็กต์ใน Ruby

ขอบเขต (Scope) เป็นแนวคิดสำคัญที่นักพัฒนา Ruby ทุกคนต้องเข้าใจ

ทำไม?

เพราะมันเป็นต้นเหตุของข้อความข้อผิดพลาดและความสับสนมากมาย

ขอบเขตคืออะไร?

ขอบเขตหมายถึงตัวแปรใดบ้างที่สามารถเข้าถึงได้ในจุดเวลาใดเวลาหนึ่ง

ประเภทตัวแปรต่างๆ มีขอบเขตที่ต่างกัน

ขอบเขตอาจ แคบมาก (ตัวแปรกลาง) หรือ กว้างมาก (ตัวแวรกลาง)

คุณควรใช้ขอบเขตที่แคบที่สุดเท่าที่จะเป็นไปได้ เพื่อหลีกเลี่ยงปัญหาการเปลี่ยนแปลงสถานะ (state mutation) และการชนกันของชื่อ (name collision)

สิ่งที่ตามมาคือรายการ ตัวอย่าง ของว่าขอบเขตส่งผลต่อโค้ด Ruby ของคุณอย่างไร

ขอบเขตของตัวแปรกลาง (Local Variables)

ตัวแปรกลางมีขอบเขตแคบที่สุด

โดยเฉพาะ ตัวแปรกลางที่ถูกกำหนดภายในเมธอดจะไม่ tồnอยู่อีกต่อไปหลังจากที่เมธอดคืนค่าแล้ว

ตัวอย่าง:

a = 50
def apple
  a = 100
  puts a
end

คุณคิดว่า apple จะพิมพ์อะไร?

คำตอบ:

เมื่อคุณเรียก apple มันจะพิมพ์ 100 เสมอ

ข้อเท็จจริงที่ว่า a ถูกกำหนด นอกเมธอด เป็น 50 ไม่มีผลต่อตัวแปร a ภายในเมธอด เลย

มันคือตัวแปรที่ต่างกัน

คุณสามารถ นึกถึงขอบเขตเหมือนฟองสบู่...

a = 50 ตัวแรกอยู่ในฟองหนึ่ง แล้วเมื่อคุณเรียกเมธอด ใดๆ ก็ตาม คุณจะเข้าสู่ฟองใหม่ที่ ว่างเปล่า

คุณไม่ได้นำตัวแปรกลางใดๆ ข้ามไปฟองใหม่

และเมื่อเมธอดจบ...

ฟองระเบิด

ตัวแปรภายในฟองหายไป และคุณไม่สามารถเข้าถึงได้

ก็คือวิธีที่ตัวแปรกลางทำงาน

ขอบเขตของตัวแปรอินสแตนซ์ (Instance Variables)

ตัวแปรอินสแตนซ์มีขอบเขตกว้างกว่า

โดยเฉพาะ ใช้สำหรับแชร์ข้อมูลภายในออบเจ็กต์ Ruby

ตัวอย่าง:

class Fruit
  def more_juice
    @quantity = 100
  end

  def less_juice
    @quantity = 50
  end
end

ในตัวอย่างนี้ @quantity เป็นตัวแปรเดียวกันสำหรับเมธอด more_juice และ less_juice ทั้งคู่

มันคือค่าที่แชร์ระหว่างเมธอด

แต่นอกคลาสนี้ และแม้บนออบเจ็กต์ Fruit ที่ต่างกัน @quantity จะต่างกันไป

ตัวอย่าง:

orange = Fruit.new
apple = Fruit.new
orange.more_juice
apple.less_juice

ทุกออบเจ็กต์มีชุดตัวแปรอินสแตนซ์ของตัวเอง

ดังนั้นในตัวอย่างนี้ orange จะมี @quantity เท่ากับ 100 และ apple จะมี @quantity เท่ากับ 50

เหมือนคนละคนมีชื่อ อายุ ประเทศ ต่างกันหละ

ขอบเขตทำงานในบล็อกอย่างไร

บล็อก (Blocks) น่าสนใจมากเมื่อพูดถึงขอบเขต

ถ้าเราตามการเปรียบเทียบฟองสบู่อีกครั้ง สิ่งที่บล็อกทำคือ นำตัวแปรกลางจากฟองปัจจุบันมาให้

คุณสามารถเข้าถึงและเปลี่ยนแปลงได้

ตัวอย่าง:

a = []
3.times { a << 1 }
p a # [1, 1, 1]

แต...

ฟองยังคงระเบิด ลบตัวแปรกลางใหม่ๆ ที่ถูกสร้างภายในบล็อกออกไป

น่าสนใจใช่ไหม?

ตัวอย่างของสิ่งที่ผมหมายถึง:

1.times { b = [1,2,3] }
b # NameError

ไม่ chỉนั้น บล็อกยังพก "ฟอง" ณ จุดที่มันถูกสร้างไปด้วย

เอฟเฟกต์ที่เรียกว่า "Closure" (คลอเจอร์)

จำไว้ว่า "ฟอง" นี้คือชุดรวมของตัวแปรทั้งหมดที่เข้าถึงได้ในจุดโค้ดเฉพาะ

มันคือขอบเขตเอง ที่บรรจุอยู่ในออบเจ็กต์

ใน Ruby เราเรียกมันว่า Binding

วิธีใช้ Ruby Bindings

แนวคิดอีกอย่างที่ผมอยากแบ่งปันในบทความนี้คือเกี่ยวกับ bindings

คุณสามารถบันทึกฟองทั้งหมดที่เราพูดถึงไว้ในออบเจ็กต์ Ruby ได้ ออบเจ็กต์ของคลาส Binding

ตัวอย่าง:

def banana
  a = 100
  binding
end

banana.class # Binding

ออบเจ็กต์ binding นี้คือฟองนั้นแหละ

คุณแม้แต่สามารถ覗มองเข้าไปในฟองและดูว่ามีอะไรอยู่ข้างใน

ตัวอย่าง:

banana.send(:local_variables) # [:a]

ขอบเขตใน Rails คืออะไร?

ขอบเขต (Scope) ใน Rails เป็นสิ่งต่างจากขอบเขตใน Ruby

แล้ว Scope ใน Rails คืออะไร?

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

ตัวอย่าง:

class User < ApplicationRecord
  scope(:with_email) { where.not(email: nil) }
end

User.with_email

อย่าสับสนกับแนวคิด scope ใน Ruby นะครับ 🙂

สรุป

คุณได้เรียนรู้เกี่ยวกับ scopes และ binding objects ใน Ruby!

จำไว้ว่า ขอบเขตกำหนดว่าคุณสามารถเข้าถึงตัวแปรใดได้ ในเวลาใดเวลาหนึ่ง

มันเหมือนฟองสบู่ ตัวแปรกลางมีฟองของตัวเอง ในขณะที่ออบเจ็กต์แชร์ฟองอีกอันสำหรับตัวแปรอินสแตนซ์

ขอบคุณที่อ่านครับ