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

เชี่ยวชาญ Ruby Constants: การกำหนด การใช้งาน และ Best Practices

Constant ใน Ruby คืออะไร?

Constant เป็นประเภทของตัวแปรที่ขึ้นต้นด้วยตัวพิมพ์ใหญ่เสมอ สามารถกำหนดได้เฉพาะ นอกเหนือจาก เมธอด เว้นแต่ใช้ metaprogramming

Constants ใช้สำหรับค่าที่ไม่ควรเปลี่ยนแปลง แต Ruby ไม่บังคับให้เปลี่ยนไม่ได้

ลักษณะแบบนี้:

FRUIT = "orange"

ตอนนี้:

เพราะ constants เป็นหัวข้อสำคัญ เราจะสำรวจรายละเอียดในบทความนี้!

วิธีการกำหนด Constants

Constant ไม่ต้องการสัญลักษณ์หรือ syntax พิเศษในการประกาศ แค่ทำให้ตัวอักษรแรกเป็นตัวพิมพ์ใหญ่

ต่อไปนี้เป็น constants ที่ถูกต้อง:

ABC = 1
Goo = 2
Foo = 3

สังเกตว่าไม่สามารถกำหนด constants ภายในเมธอดได้

จะได้ error message นี้:

def the_method
  ABC = 1
end
# "dynamic constant assignment"

จึงควรกำหนด constants นอกเมธอด ปกติจะวางไว้บนสุดของ class เพื่อมองเห็นชัด

class RubyBlog
  URL = "rubyguides.com"
  AUTHOR = "Jesus Castello"
end

เข้าถึง constants เหล่านี้ได้จากในเมธอดของ class หรือนอก class ด้วย syntax:

p RubyBlog::AUTHOR # "Jesus Castello"

เราจะพูดถึง scope ของ constants ต่อไป ค่อยติดตาม!

Uninitialized Constant Error

Error พบบ่อยคือ:

puts Foo # "uninitialized constant Foo (NameError)"

แปลในใจว่า "constant not found"

จุดสำคัญ: Ruby classes เป็น constants

ตัวอย่าง:

Array
String
Hash

เป็น constants เพราะตัวอักษรแรกพิมพ์ใหญ่

ตอน define class คุณสร้าง object Class มอบหมายให้ constant ชื่อ class นั้น

ทำไมสำคัญ?

เพราะสาเหตุส่วนใหญ่ของ "uninitialized constant" error คือลืม require ไฟล์หรือ gem ที่กำหนด constant นั้น หรือสะกดชื่อผิด

จงระวัง!

Constants เปลี่ยนแปลงได้

เหมือนกล่าวไว้ Ruby constants เปลี่ยนได้

ตัวอย่าง:

ABC = 1
ABC = 2

แต่จะได้ warning:

2: warning: already initialized constant ABC

โปรแกรมยังทำงานได้ แต่อย่าทำบ่อย

ไม่มีวิธีป้องกันไม่ให้ constant เปลี่ยน เพราะตัวแปรใน Ruby ไม่ใช่ container แค่ pointer ไปยัง object หรือ label ก็ได้

ทำได้ดีสุดคือใช้ immutable objects

ตัวอย่าง:

AUTHOR = "Jesus Castello".freeze
AUTHOR << "o" # RuntimeError: can't modify frozen String

บทความเกี่ยวข้อง: Ruby mutability และ freeze method

ในตัวอย่างนี้ ยังเปลี่ยนได้ว่า AUTHOR ชี้ไปไหน freeze ป้องกันแค่การเปลี่ยน object เอง

Constant Methods

มีเมธอดเฉพาะสำหรับจัดการ constants:

Method คำอธิบาย
constants คืนค่า array ของ symbols แทน constants ที่กำหนดใน class
const_get คืนค่าของ constant รับ parameter เป็น symbol หรือ string
const_set ตั้งค่า constant รับ 2 parameters: ชื่อ constant เป็น symbol และค่า constant
const_missing เหมือน method_missing แต่สำหรับ constants
const_defined? คืน true ถ้า constant ที่กำหนด (เป็น symbol) ถูก define แล้ว
remove_const ลบ constant
private_constant ทำให้ constant เป็น private เข้าถึงนอก class ด้วย Class::ABC ไม่ได้

มี metaprogramming tricks ใช้เมธอดเหล่านี้ได้

ตัวอย่าง:

module Food
  class Bacon; end
  class Chocolate; end
end
puts "Classes defined inside #{Food}:"
puts Food.constants

ยังใช้ string เช่น "Array" ได้ class จริง:

array_class = Object.const_get("Array")

แต่ระวัง เพราะผู้ใช้อาจ inject code ได้ถ้า string มาจาก params หรือ user input

ใน Rails มี constantize method ทำ const_get ให้ แต่ไม่ทำ security checks

CheatSheet

เชี่ยวชาญ Ruby Constants: การกำหนด การใช้งาน และ Best Practices

Ruby Constant Scope

สร้าง constant นอก class ทุกอย่าง ที่ top-level จะเข้าถึงได้ทุกที่

Constants ยังเข้าถึงได้ใน child classes

class A
  FOO = 1
end
class B < A
  def foo
    puts FOO
  end
end
B.constants # [:FOO]

Constants ที่กำหนดนอก nested module/class เข้าถึงได้ใน nested classes

module Food
  STORE_ADDRESS = "The moon"
  class Bacon
    def foo; puts STORE_ADDRESS; end
  end
end
fb = Food::Bacon.new
fb.foo # "The moon"

Module Mixing

Constants จาก mixed-in modules เข้าถึงได้:

module Mixin
  A = 123
end
class Product
  include Mixin
  puts A
end
# 123

สังเกต: ทำงานตอน include module ไม่ทำงานถ้า extend

ตัวอย่าง:

class Product
  extend Mixin
  puts A
end
# uninitialized constant Product::A

อีกอย่าง:

ใช้เมธอดที่ include จาก module Ruby จะหา constants เริ่มจากที่เมธอดถูก define

ตัวอย่าง:

module Parent
  def print_value
    VALUE
  end
end
class Child
  include Parent
  VALUE = 1
end
# Works
p Child::VALUE
# uninitialized constant Parent::VALUE
p Child.new.print_value

ควรจำไว้!

Module Nesting

อีกตัวอย่าง nested classes (modules เหมือนกัน)

class A
  FOO = 1
end
class A::B
  class C
    puts FOO
  end
end

สังเกต notation A::B ที่ลองใช้เป็น shortcut แต่ class C จะเข้าถึง FOO โดยตรงไม่ได้

จึงควรใช้ nesting แบบนี้:

class A
  FOO = 1
end
class A
  class B
    class C
      puts FOO
    end
  end
end

ตัวอย่างแรก ยังทำ ::A::FOO ได้ แต่ถ้าชื่อ class เปลี่ยนจะ error

Syntax ::A::FOO ทำงานเพราะบอก Ruby ให้หาใน top-level scope ที่ constants เช่น Array และ String อยู่

Video

สรุป

คุณเรียนรู้ Ruby constants ตัวแปรประเภทหนึ่งที่มีพฤติกรรมน่าสนใจ สามารถเปลี่ยนค่าได้แต่จะมี warning

ยังเรียนรู้ว่า class names เป็น constants และควรหลีกเลี่ยง const_get กับ user input

ถ้าชอบโพสต์นี้ อย่าลืมแชร์ ให้คนอื่นเข้าใจ constants ได้