ตัวแปรและขอบเขตของตัวแปร ในภาษา Ruby
ในบทก่อนหน้า คุณได้เรียนรู้เกี่ยวกับตัวแปรในเบื้องต้นไปแล้ว นั่นเป็นพื้นฐานสำหรับตัวแปรที่ต้องรู้ก่อนเริ่มเขียนโปรแกรมในภาษา Ruby ในบทนี้ คุณจะได้เรียนรู้เพิ่มเติมเกี่ยวกับตัวแปร เช่น ขอบเขตของตัวแปร ตัวแปรประเภทต่างๆ และนี่เป็นเนื้อหาของบทนี้
- Ruby local variables
- Blocks and methods
- Ruby global variables
- Ruby instance variables
- Ruby class variables
- Ruby predefined constant variables
- Ruby predefined global variables
Ruby local variables
ตัวแปร local เป็นตัวแปรที่สามารถใช้ได้ในขอบเขตที่ถูกสร้างขึ้น หรือเรียกว่า local scope ในภาษา Ruby นั้นขอบเขตใหม่จะถูกสร้างขึ้นเมื่อสร้างเมธอดหรือบล็อค นั่นหมายความว่า ตัวแปรที่ประกาศภายในเมธอดจะสามารถใช้ได้ในเมธอดนั้นเท่านั้น นอกจากนี้ Ruby ยังมีส่วนของโปรแกรมหลัก (Main execution area) หรือ Ruby toplevel ซึ่งเป็นขอบเขตสูงสุดของโปรแกรม มาดูตัวอย่าง
# Main execution area
x = 10
def method1
x = 20
puts "x in method1 #{x}"
end
puts "x in main #{x}"
method1
ในตัวอย่าง แสดงให้เห็นถึงขอบเขต local สองขอบเขตที่ถูกสร้างขึ้น ส่วนแรกอยู่ในส่วนของโปรแกรมหลัก เราได้ประกาศตัวแปร x และกำหนดค่าเป็น 10 และขอบเขตที่สองอยู่ภายในเมธอด method1 ที่มีการประกาศตัวแปร x เช่นเดียวกัน แต่มีค่าเป็น 20 และสิ่งที่เกิดขึ้นคือตัวแปรทั้งสองนั้นอยู่คนละขอบเขตกัน และนั่นหมายความว่ามันเป็นคนละตัวแปรกัน
x in main 10
x in method1 20
และนี่เป็นผลลัพธ์จากการรันไฟล์โปรแกรม local_variable1.rb จะเห็นว่าค่าของตัวแปรทั้งสองจะเป็นคนละค่ากัน มาดูตัวอย่างถัดไป
# Main execution area
x = 10
def method1
puts "x in method1 #{x}" # Error
end
puts "x in main #{x}"
method1
ในตัวอย่างนี้ เราได้ประกาศตัวแปร x ในส่วนหลักของโปรแกรมเช่นเดิม แต่ไม่มีการประกในเมธอด method1 แล้ว และเนื่องจากภายในเมธอดเราได้เข้าถึงตัวแปร x ที่ไม่ได้ประกาศในเมธอด โปรแกรมจะเกิดข้อผิดพลาดขึ้นเมื่อเรารัน
x in main 10
Traceback (most recent call last):
1: from local_variable2.rb:9:in `<main>'
local_variable2.rb:5:in `method1': undefined local variable or method `x' for main:Object (NameError)
และนี่เป็นผลลัพธ์ของการรันโปรแกรม local_variable2.rb ซึ่งจะเกิดข้อผิดพลาดโดยแจ้งว่าตัวแปร x ไม่ได้ถูกประกาศในเมธอด
ตัวอย่างต่อไป มาดูตัวอย่างของขอบเขตตัวแปรที่ซับซ้อนขึ้นเล็กน้อย
a = 1
b = 2
def method1
c = 3
d = 4
puts "Local variables in method1"
puts local_variables.inspect
def method2
e = -8
f = -9
puts "Local variables in method2"
puts local_variables.inspect
end
method2
end
def method3
a = 10
b = 20
puts "Local variables in method3"
puts local_variables.inspect
end
puts "Local variables in main"
puts local_variables.inspect
method1
method3
ในตัวอย่าง ในส่วนของโปรแกรมหลัก เราได้ประกาศตัวแปรสองตัวคือ a และ b และสองเมธอดคือ method1 และเมธอด method3 โดยแต่ละเมธอดนั้นมีการประกาศตัวแปร local เป็นของตัวเอง
def method1
c = 3
d = 4
puts "Local variables in method1"
puts local_variables.inspect
def method2
e = -8
f = -9
puts "Local variables in method2"
puts local_variables.inspect
end
method2
end
ในเมธอด method1 นอกจากจะมีการประกาศตัวแปรแล้ว ยังมีการประกาศเมธอดอยุ่ข้างในอีกด้วย เมธอด method2 นั้นเป็นเมธอดที่มีขอบเขตภายในเมธอด method1 ซึ่งในภาษา Ruby นั้น คุณเมธอดสามารถที่จะประกาศซ้อนกันได้ แต่ในการที่จะเรียกใช้งานเมธอด method2 คุณต้องเรียกในขอบเขตที่มันถูกประกาศขึ้นมาเท่านั้น นั่นก็คือภายในเมธอด method1 นั่นเอง
puts local_variables.inspect
จากคำสั่งด้านบน การเรียกใช้งานเมธอด local_variables นั้นจะได้อาเรย์ของ symbol ของตัวแปรในขอบเขตที่มันถูกเรียก หลังจากนั้นเราใช้เมธอด inspect เพื่อแปลงอาเรย์ให้อยู่ในรูปแบบของ String ที่สามารถแสดงผลได้
Local variables in main
[:a, :b]
Local variables in method1
[:c, :d]
Local variables in method2
[:e, :f]
Local variables in method3
[:a, :b]
นี่เป็นผลลัพธ์ของการรันโปรแกรม จะเห็นว่าตัวแปรที่เราได้ประกาศนั้นจะอยู่ในขอบเขตที่มันถูกสร้างเท่านั้น
Blocks and methods
บล็อค (Blocks) นเป็นไวยากรณ์ทางภาษาที่ใช้สำหรับรันส่วนของโปรแกรมในขอบเขตของมันเอง ในภาษา Ruby คุณสามารถสร้างบล็อคด้วยเครื่องหมาย {...} หรือคำสั่ง do และ end อย่างไรก็ตาม บล็อคนั้นไม่สามารถสร้างขึ้นมาอย่างโดดเดี่ยวได้ แต่มันจะถูกสร้างเมื่อต้องการส่งเป็นพารามิเตอร์ของเมธอด หรือใช้ร่วมกับคำสั่งในภาษา Ruby
มาดูตัวอย่างการสร้างบล็อคในภาษา Ruby
BEGIN {
puts "Program started"
}
END {
puts "Program stopped"
}
[1, 2, 3].each do |x|
puts x
end
ในตัวอย่าง เราได้สร้างบล็อคมาสามบล็อค โดยสองบล็อคแรกนั้นใช้เครื่องหมาย {...} ในการสร้าง ส่วนบล็อคสุดท้ายใช้คำสั่ง do ... end ในการสร้าง ซึ่งทั้งสองวิธีนี้ได้ผลลัพธ์ที่เหมือนกัน
อย่างที่เราได้บอกไป บล็อคมักจะถูกสร้างขึ้นเพื่อใช้ร่วมกับเมธอดหรือคำสั่งในภาษา Ruby คำสั่ง BEGIN นั้นจะรับค่าบล็อคเป็นพารามิเตอร์ ซึ่งจะทำงานในตอนโปรแกรมเริ่ม ในขณะที่คำสั่ง END จะทำงานในตอนที่โปรแกรมสิ้นสุด
และสุดท้ายใน main โปรแกรม เราใช้เมธอด each ของอาเรย์ โดยเมธอดนี้จะส่งแต่ละค่าในอาเรย์เข้าไปรันในบล็อคผ่านทางตัวแปร x ซึ่งเป็นพารามิเตอร์ของบล็อค โดยที่เครื่องหมาย | (pip) นั้นใช้สำหรับกำหนดพารามิเตอร์ในบล็อค
Program started
1
2
3
Program stopped
นี่เป็นผลลัพธ์การทำงานของโปรแกรม สังเกตุว่าลำดับการรันของบล็อคนั้นไม่ได้รันตามลำดับที่มันประกาศ อันเนื่องมาจากการงานของคำสั่ง BEGIN และ END นั่นเอง
เมื่อคุณทำงานกับบล็อคในภาษา Ruby นั้นจะมีความแตกต่างจากเมธอดอยู่คือ ในบล็อคนั้นคุณสามารถเข้าถึงค่าของตัวแปรในขอบเขตที่สูงขึ้นไปได้ มาดูตัวอย่างต่อไปนี้
x = 10
y = 20
4.times { |x|
puts "x inside the block: #{x}"
puts "y inside the block: #{y}"
}
puts "x outside the block: #{x}"
ในตัวอย่าง เราได้ประกาศตัวแปร x และ y ที่ส่วนหลักของโปรแกรม หลังจากนั้นเราสร้างบล็อคที่มีการประกาศตัวแปร x ด้วย นั่นทำให้เมื่อคุณเข้าถึงและแก้ไขตัวแปร x ภายในบล็อค นั่นจะส่งผลกับค่าของตัวแปรภายในบล็อคเท่านั้น
ต่อมาในบล็อคนั้นได้มีการเรียกใช้ตัวแปร y เมื่อคุณทำเช่นนี้ ถ้าหากตัวแปร y ไม่ได้ประกาศในบล็อค Ruby จะมองหาตัวแปรในขอบเขตที่สูงขึ้นไปเรื่อยๆ จนกว่าจะเจอ ซึ่งคุณไม่สามารถทำเช่นนี้ได้กับเมธอด
x inside the block: 0
y inside the block: 20
x inside the block: 1
y inside the block: 20
x inside the block: 2
y inside the block: 20
x inside the block: 3
y inside the block: 20
x outside the block: 10
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม ค่าของตัวแปร x นั้นจะเป็นค่าในขอบเขตที่มันถูกสร้างขึ้น ในขณะที่ตัวแปร y นั้นในบล็อคจะใช้ค่าจากส่วนของโปรแกรมหลัก
Ruby global variables
ตัวแปร global เป็นตัวแปรที่สามารถเข้าถึงได้จากทุกส่วนของโปรแกรมหลังจากที่มันถูกประกาศ ซึ่งจะตรงกันข้ามกับตัวแปร local ที่จะสามารถเข้าถึงได้ภายในขอบเขตที่มันถูกสร้างขึ้นเท่านั้น ในภาษา Ruby ตัวแปร global จะขึ้นต้นด้วยเครื่องหมาย $
มาดูตัวอย่างการประกาศและใช้งานตัวแปร global ในภาษา Ruby
$gb = 1
module M
puts "Inside module #{$gb}"
end
class O
def initialize
puts "Inside class's method #{$gb}"
end
end
def hello
puts "Inside module #{$gb}"
end
puts "In main #{$gb}"
hello
ob = O.new
ในตัวอย่างนั้นเป็นการประกาศและใช้งานตัวแปร global ซึ่งเราได้ประกาศตัวแปร global $gb ที่มีค่าเป็น 1 หลังจากนั้นเราเข้าถึงตัวแปรในโมดูล คลาส และเมธอด ซึ่งนี่แสดงให้เห็นว่าตัวแปร global นั้นสามารถเข้าถึงได้ทุกที่ภายในโปรแกรม
Inside module 1
In main 1
Inside module 1
Inside class's method 1
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม อย่างไรก็ตาม การใช้ตัวแปร global เป็นจำนวนมากนั้นเป็นเรื่องที่ไม่แนะนำ คุณควรใช้มันเท่าที่จะเป็นเท่านั้น เพราะการใช้ตัวแปร global นั้นสามารถทำให้โค้ดซับซ้อนขึ้นได้
นอกจากการอ่านค่าจากตัวแปร global แล้ว คุณก็ยังสามารถกำหนดค่าให้กับตัวแปร global ที่คุณสร้างขึ้นมาได้เช่นกัน มาดูตัวอย่างต่อไปนี้
$expressions = []
$last_result = nil
def add(a, b)
result = a + b
exp = "#{a} + #{b} = #{result}"
$expressions.push(exp)
$last_result = result
return result
end
def sub(a, b)
result = a - b
exp = "#{a} - #{b} = #{result}"
$expressions.push(exp)
$last_result = result
return result
end
def multiply(a, b)
result = a * b
exp = "#{a} * #{b} = #{result}"
$expressions.push(exp)
$last_result = result
return result
end
def divide(a, b)
result = a / b
exp = "#{a} / #{b} = #{result}"
$expressions.push(exp)
$last_result = result
return result
end
puts add(1, 2)
puts sub(3, 5)
puts divide(8, 7)
puts multiply(4, 9)
puts "Performed expressions:"
p $expressions
puts "Last result: #{$last_result}"
ในตัวอย่าง เป็นการใช้ประโยชน์จากตัวแปร global เพื่อเก็บนิพจน์ของการคำนวณทั้งหมดที่เกิดขึ้น โดยเมธอดเหล่านี้จะรับพารามิเตอร์สองตัวคือ a และ b แล้วหลังจากนั้นคำนวณเพื่อหาผลบวก ลบ คูณ และหาร หลังจากนั้นส่งค่าผลลัพธ์กลับมา
$expressions = []
$last_result = nil
ในตอนแรก เราได้ประกาศตัวแปร global $expressions ซึ่งเป็นตัวแปรอาเรย์สำหรับเก็บนิพจน์ในรูปแบบ String และตัวแปร $last_result สำหรับเก็บผลลัพธ์จากการคำนวณของเมธอด โดยตัวแปรนี้จะเปลี่ยนค่าไปเรื่อยๆ ทุกครั้งที่มีการเรียกเมธอด
def add(a, b)
result = a + b
exp = "#{a} + #{b} = #{result}"
$expressions.push(exp)
$last_result = result
return result
end
ในแต่ละเมธอด เราได้ทำการคำนวณหาผลลัพธ์และเก็บไว้ในตัวแปร result และสร้างนิพจน์ไว้ในตัวแปร exp และเนื่องจากตัวแปร $expressions นั้นเป็นอาเรย์ เราได้ใช้เมธอด push สำหรับเก็บข้อมูลเข้าอาเรย์ และเก็บผลลัพธ์จากการคำนวณของเมธอดไว้ในตัวแปร $last_result
3
-2
1
36
Performed expressions:
["1 + 2 = 3", "3 - 5 = -2", "8 / 7 = 1", "4 * 9 = 36"]
Last result: 36
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม
Ruby instance variables
ตัวแปร Instance หรือแอตทริบิวต์ คือตัวแปรที่ขึ้นต้นด้วยเครื่องหมาย @ และต้องประกาศในคลาส หรือกล่าวอีกนัยหนึ่ง มันเป็นแอตทริบิวต์ของออบเจ็ค ในการเขียนโปรแกรมเชิงวัตถุ (OOP) ตัวแปร Instance นั้นเป็นพื้นที่สำหรับเก็บข้อมูลของออบเจ็ค ซึ่งโดยทั่วไปแล้วออบเจ็คจะถูกสร้างมากจากคลาส และคลาสนั้นเป็นเหมือนแม่แบบที่ใช้กำหนดว่าออบเจ็คนั้นจะมีแอตทริบิวต์ และเมธอดอะไรบ้าง
มาดูตัวอย่างการประกาศและใช้งานตัวแปร Instance
class Box
attr_accessor(:width, :height)
def initialize(width, height)
@width = width
@height = height
end
def area()
return @width * @height
end
end
b1 = Box.new(2, 3)
b2 = Box.new(4, 6)
puts "Box1: w = #{b1.width}, h = #{b1.height}, area = #{b1.area()}"
puts "Box2: w = #{b2.width}, h = #{b2.height}, area = #{b2.area()}"
b2.width = 5
b2.height = 8
puts "Box2: w = #{b2.width}, h = #{b2.height}, area = #{b2.area()}"
ในตัวอย่าง เราได้ประกาศคลาส Box ด้วยคำสั่ง class และสิ้นสุดด้วยคำสั่ง end
def initialize(w, h)
@width = w
@height = h
end
ในเมธอด initialize เราได้ประกาศตัวแปร @width และ @height ซึ่งโดยทั่วไปแล้วตัวแปร Instance นั้นจะประกาศในเมธอด initialize โดยเมธอดนี้จะทำงานเมื่อออบเจ็คถูกสร้างขึ้นด้วยเมธอด Box.new ซึ่งพารามิเตอร์ในเมธอด initialize นั้นจะรับมาจากตอนที่เราสร้างออบเจ็คด้วยเมธอด Box.new
attr_accessor(:width, :height)
คำสั่ง attr_accessor นั้นใช้สำหรับสร้าง Getter และ Setter ให้กับแอตทริบิวต์ นั่นจำทหให้เราสามารถอ่านและเปลี่ยนแปลงแอตทริบิวต์จากภายนอกคลาสได้
def area()
return @width * @height
end
ต่อมาภายในคลาสเราได้ประกาศเมธอด area ซึ่งใช้สำหรับคำนวณพื้นที่จากความยาวและความสูง จากแอตทริบิวต์ของออบเจ็ค
b1 = Box.new(2, 3)
b2 = Box.new(4, 6)
puts "Box1: w = #{b1.width}, h = #{b1.height}, area = #{b1.area()}"
puts "Box2: w = #{b2.width}, h = #{b2.height}, area = #{b2.area()}"
หลังจากนั้นเราสร้างสองออบเจ็คจากคลาส Box นั่นคือ b1 และ b2 ซึ่งแต่ละออบเจ็คนั้นจะมีค่าความยาวและความสูงเป็นของตัวเอง หลังจากนั้นเป็นการแสดงความยาว ความสูงและพื้นที่ของกล่องออกมา
b2.width = 5
b2.height = 8
puts "Box2: w = #{b2.width}, h = #{b2.height}, area = #{b2.area()}"
นอกจากการอ่านค่าจากแอตทริบิวต์แล้ว เรายังสามารถกำหนดค่าใหม่ให้มันได้ ในตัวอย่างเราเปลี่ยนความยาวและความสูงของออบเจ็ค b2 และแสดงข้อมูลอีกครั้ง
Box1: w = 2, h = 3, area = 6
Box2: w = 4, h = 6, area = 24
Box2: w = 5, h = 8, area = 40
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม instance_variable.rb
Ruby class variables
ตัวแปรคลาส (Class variable) เป็นตัวแปรที่ใช้สำหรับแชร์ค่าระหว่างออบเจ็คที่สร้างจากคลาสนั้นๆ กล่าวคือ มันไม่ผูกอยู่กับออบเจ็คใดออบเจ็คหนึ่งเหมือนกับตัวแปร Instance ด้วยเหตุนี้ ตัวแปรคลาสจึงมีไว้สำหรับเก็บข้อมูลที่ใช้ร่วมกันสำหรับออบเจ็ค ตัวแปรคลาสจะขึ้นต้นด้วยเครื่องหมาย @@ มาดูตัวอย่างการใช้งานตัวแปรคลาสในภาษา Ruby
class Person
@@instances = 0
attr_accessor :name, :age
def initialize(name, age)
@@instances += 1
@name = name
@age = age.to_i
end
def inspect
"#{name} (#{age})"
end
def self.total
@@instances
end
end
p1 = Person.new("Mateo", 10)
p2 = Person.new("Julia", 7)
p3 = Person.new("Luke", 9)
puts "Total object created: #{Person.total}"
puts p1.inspect
puts p2.inspect
puts p3.inspect
ในตัวอย่าง เรามีคลาส Person ซึ่งมีตัวแปร instance สองตัวแปรคือ @name และ @age สำหรับเก็บชื่อและอายุ และนอกจากนี้เรายังประกาศตัวแปรคลาส @@instances และกำหนดค่าเป็น 0โดยตัวแปรนี้จะใช้เพื่อนับว่าออบเจ็คของคลาสนี้ได้ถูกสร้างไปแล้วเท่าไหร่
def initialize(name, age)
@@instances += 1
@name = name
@age = age.to_i
end
เมื่อออบเจ็คถูกสร้างด้วยเมธอด Person.new นั่นจะทำให้เมธอด initialize ทำงาน ดังนั้นเราทำการเพิ่มค่าของตัวแปร @@instances ในเมธอดดังกล่าว นั่นจะทำให้ค่าของตัวแปรเพิ่มขึ้นทุกครั้งที่มีการสร้างออบเจ็คใหม่
def self.total
@@instances
end
ในคลาส Person นั้นเราสามารถเข้าถึงตัวแปรคลาสด้วยชื่อตัวแปรได้เลย แต่ถ้าหากเราต้องการเข้าถึงตัวแปรคลาสภายนอกคลาส เราต้องสร้างเมธอดเพื่อเป็น Getter สำหรับตัวแปรคลาสดังกล่าว โดยเมธอด total นั้นถูกสร้างเป็นคลาสเมธอดโดยมีคำสั่ง self. นำหน้า ซึ่งเราสามารถเรียกใช้เมธอดผ่านทางชื่อคลาสตามด้วยชื่อเมธอด Person.total
p1 = Person.new("Mateo", 10)
p2 = Person.new("Julia", 7)
p3 = Person.new("Luke", 9)
puts "Total object created: #{Person.total}"
หลังจากที่เราสร้างคลาสเสร็จเรียบร้อยแล้ว ต่อไปเรานำคลาส Person มาสร้างออบเจ็คทั้งหมด 3 ออบเจ็ค หลังจากนั้นเราเรียกใช้คลาสเมธอด total เพื่อดูว่ามีกี่ออบเจ็คที่ถูกสร้างไปแล้ว
Total object created: 3
Mateo (10)
Julia (7)
Luke (9)
นี่เป็นผลลัพธ์การทำงานของโปรแกรม จะเห็นว่าออบเจ็คได้ถูกสร้างไปสามครั้ง ซึ่งเป็นผลจากค่าที่นับด้วยตัวแปรคลาส @@instances หลังจากนั้นเราแสดงรายละเอียดของแต่ละออบเจ็คด้วยการเรียกเมธอด inspect
นอกจากการอ่านค่าจากตัวแปรคลาสแล้ว คุณยังสามารถกำหนดค่าให้กับตัวแปรคลาสในขณะที่โปรแกรมทำงานเช่นเดียวกัน เพื่อทำเช่นนั้นคุณต้องสร้างคลาสเมธอดเพื่อเป็น Setter สำหรับตัวแปรดังกล่าว มาดูตัวอย่างกัน
class Person
@@last_name_first = false
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def full_name
if @@last_name_first
return "#{@last_name} #{@first_name}"
else
return "#{@first_name} #{@last_name}"
end
end
def self.last_name_first=(value)
@@last_name_first = value
end
end
p1 = Person.new("Luke", "Chavez")
p2 = Person.new("Bernard", "Green")
# By default, show first name first
puts p1.full_name
puts p2.full_name
# Show last name first
Person.last_name_first = true
puts p1.full_name
puts p2.full_name
ในตัวอย่าง เราได้ประกาศคลาส Person ซึ่งคลาสนี้มีตัวแปรสองตัวแปรคือ @first_name และ @last_name ที่ใช้สำหรับเก็บชื่อและนามสกุลของบุคคลที่จะนำมาสร้างออบเจ็ค
@@last_name_first = false
นอกจากนี้ เรายังมีตัวแปรคลาส @@last_name_first ซึ่งเป็นตัวแปรประเภท boolean ซึ่งกำหนดรูปแบบของชื่อว่าจะให้นามสกุลขึ้นก่อนหรือไม่ ถ้าหากตัวแปรนี้มีค่าเป็น true โปรแกรมจะแสดงชื่อก่อนนามสกุล และถ้าหากมีค่าเป็น false ซึ่งเป็นค่าปริยาย จะแสดงชื่อก่อนนามสกุล
def full_name
if @@last_name_first
return "#{@last_name} #{@first_name}"
else
return "#{@first_name} #{@last_name}"
end
end
เมธอด full_name ใช้สำหรับรับค่าชื่อแบบเต็ม โดยจะแสดงชื่อก่อนหรือนามสกุลก่อนนั้นึ้นอยู่กับตัวแปรคลาส @@last_name_first
def self.last_name_first=(value)
@@last_name_first = value
end
คลาสเมธอด last_name_first= นั้นเป็นเมธอดสำหรับเปลี่ยนค่าตัวแปรคลาส @@last_name_first ซึ่งในภาษา Ruby นั้นคุณสามารถใช้สัญลักษณ์ในการตั้งชื่อเมธอดได้ ในกรณนี้เครื่องหมาย = นั้นเป็นส่วนหนึ่งของชื่อเมธอด
p1 = Person.new("Luke", "Chavez")
p2 = Person.new("Bernard", "Green")
# By default, show first name first
puts p1.full_name
puts p2.full_name
# Show last name first
Person.last_name_first = true
puts p1.full_name
puts p2.full_name
หลังจากนั้น เราได้สร้างออบเจ็คสองออบเจ็คจากคลาส Person และเรียกใช้เมธอด full_name สำหรับแสดงชื่อของบุคคล หลังจากนั้นเราเปลี่ยนค่าแปรคลาส @@last_name_first เป็น true ผ่านทางเมธอด last_name_first= และแสดงชื่อของบุคคลอีกครั้ง
Luke Chavez
Bernard Green
Chavez Luke
Green Bernard
และนี่เป็นผลลลัพธ์การทำงานของโปรแกรม สองบรรทัดแรกโปรแกรมจะแสดงชื่อก่อนนามสกุล สองบรรทัดต่อมาโปรแกรมแสดงนามสกุลก่อนชื่อจากผลที่เราเปลี่ยนตัวแปรคลาส @@last_name_first ซึ่งจะส่งผลกับทุกออบเจ็คที่ใช้คลาสนี้นั่นเอง
Ruby predefined constant variables
ตัวแปรค่าคงที่นั้นเป็นตัวแปรที่มีค่าเพียงหนึ่งเดียว โดยตัวแปรเหล่านี้เป็น instance ของคลาสในภาษา Ruby
self นั้นเป็นตัวแปรที่ใช้สำหรับอ้างถึงเมธอดหรือออบเจ็คในบริษทที่ใช้งานปัจจุบัน nil นั้นหมายการไม่มีค่าอะไรอยู่เลย true นั้นหมายถึงค่าทางตรรกศาสร์ที่มีค่าเป็นจริง และ false นั้นหมายถึงค่าทางตรรกศาสตร์ที่มีค่าเป็นเท็จ
p self
p nil
p true
p false
p self.class
p nil.class
p true.class
p false.class
ในตัวอย่างของการใช้งานตัวแปร pseudo เราได้แสดงค่าของตัวแปรด้วยเมธอด p และแสดงคลาสของตัวแปรทั้งหมดออกมา
p self
ในคำสั่งนี้ self จะส่งค่ากลับเป็นบริษทของส่วนหลักของโปรแกรม
main
nil
true
false
Object
NilClass
TrueClass
FalseClass
และนี่เป็นผลลัพธ์การทำงานของโปรแกรมที่แสดงค่าของตัวแปร pseudo ทั้งหมดและคลาสที่ตัวแปรเหล่านั้น
ต่อไปมาดูตัวอย่างการนำใช้ self และ nil ไปใช้ในการเขียนโปรแกรมในภาษา Ruby
class Fruit
def initialize(name, color, weight = nil)
@name = name
@color = color
@weight = weight
end
def set_color(color)
@color = color
self
end
def set_weight(weight)
@weight = weight
self
end
def info
print "#{@name} has #{@color.downcase} color"
if @weight
print " and #{@weight} Gram of weight"
end
puts
end
end
f1 = Fruit.new("Apple", "Red")
f2 = Fruit.new("Banana", "Yellow", 80)
f1.info
f2.info
f1.set_color("Green").set_weight(120)
f1.info
ในตัวอย่างนั้น เราได้ประกาศคลาส Fruit ซึ่งเป็นคลาสสำหรับเก็บชื่อ สี และน้ำหนักของผลไม้ สังเกตุว่าในเมธอด initialize ในพารามิเตอร์ weight ของเมธอดเป็นการกำหนดค่า default ให้กับพารามิเตอร์ดังกล่าว นั่นหมายความว่าในตอนสร้างออบเจ็คด้วยเมธอด new เราสามารถละเว้นการส่งค่านี้มาได้ และค่าของตัวแปรนี้จะเป็น nil
def info
print "#{@name} has #{@color.downcase} color"
if @weight
print " and #{@weight} Gram of weight"
end
puts
end
ต่อมาเราได้สร้างเมธอด info เพื่อให้แสดงข้อมูลของผลไม้ โดยแสดงชื่อ สี และน้ำหนักออกมา สำหรับการแสดงน้ำหนักนั้นเราได้ใช้คำสั่ง ifตรวจสอบก่อนว่ามีค่าหรือไม่ ซึ่งถ้าหากค่าของ @weight เป็น nil นั้นหมายความไม่มีค่าอยู่นั่นเอง นั่นจะทำให้ในคำสั่ง if จะไม่ถูกทำงาน
f1 = Fruit.new("Apple", "Red")
f2 = Fruit.new("Banana", "Yellow", 80)
f1.info
f2.info
ต่อมาเราสร้างออบเจ็คมาสองออบเจ็คจากคลาส Fruit ออบเจ็คแรกเราได้ละเว้นพารามิเตอร์ที่สาม นั่นจะส่งผลให้ค่า @weight ของออบเจ็คนี้เป็น nil และสำหรับออบเจ็คที่สองเราส่งพารามิเตอร์ครบทุกตัว และหลังจากนั้นเราแสดงข้อมูลของออบเจ็คผลไม้ด้วยเมธอด info
def set_color(color)
@color = color
self
end
def set_weight(weight)
@weight = weight
self
end
นอกจากนี้ในคลาส Fruit เรายังได้กำหนด Setter เมธอดสำหรับตัวแปร @color และ @weight สังเกตุว่าภายในเมธอดทั้งสอง หลังจากที่กำหนดค่าใหม่ให้กับตัวแปรแล้ว เราได้ส่งค่าตัวแปร self กลับ ซึ่งหมายถึงออบเจ็คในบริษทปัจจุบันกลับไป
f1.set_color("Green").set_weight(120)
f1.info
และเนื่องจากทั้งเมธอด set_color และ set_weight ส่งค่ากลับมาเป็น self และ self นั้นมีค่าเท่ากับตัวแปร f1 นั่นทำให้เราสามารถเรียกใช้งานเมธอดแบบ chain ได้ ซึ่งเป็นสิ่งที่คุณจะพบได้บ่อยในภาษา Ruby
Apple has red color
Banana has yellow color and 80 Gram of weight
Apple has green color and 120 Gram of weight
และนี่เป็นผลลัพธ์ของการรันโปรแกรมสำหรับตัวอย่างการใช้งาน self และ nil
ต่อไปเป็นตัวอย่างการใช้งานค่า true และ false ซึ่งความจริงแล้วสองค่านี้เป็นค่าของ boolean กล่าวคือมันเป็นข้อมูลประเภท boolean นั้นเอง แต่อย่างไรก็ตามมันถูกสร้างมาจากคนละคลาสนั้นคือคลาส TrueClass และคลาส FalseClass ตามลำดับ
ค่า boolean นั้นเป็นค่าที่มีเพียงสองค่าเท่านั้นนั่นคือ true และ false แต่อย่างไรก็ตาม ในการเขียนโปรแกรมจริงๆ นั้นเราอาจจะใช้ค่าอื่นแทนก็ได้ ยกตัวอย่างเช่น 1 และ 0 สำหรับตอนนี้เราจะมาคุณมาทำความเข้าใจเกี่ยวกับการใช้งาน true และ false ในภาษา Ruby
like = true
if like
puts "I like Ruby language"
end
ในตัวอย่างด้านบน เราได้ประกาศตัวแปร like และกำหนดค่าเป็น true ซึ่งโดยทั่วไปแล้วค่าของ boolean นั้น คำสั่ง if นั้นเป็นคำสั่งควบคุมที่รับเงื่อนไขเป็นค่าของ boolean ซึ่งถ้าหากเงื่อนไขเป็นจริง โปรแกรมทำงานในบล็อคของคำสั่ง if
Ruby predefined variables
ในภาษา Ruby มีตัวแปรที่กำหนดไว้ล่วงหน้า (predefined variable) จำนวนหนึ่ง เพื่ออำนวยความสะดวกให้กับโปรแกรมเมอร์ในการเขียนโปรแกรม ซึ่งตัวแปรเหล่านี้นั้นเป็นตัวแปร global เนื่องจากมันขึ้นต้นด้วยเครื่องหมาย $
สำหรับบทนี้ เราจะแสดงตัวอย่างการใช้งานสำหรับตัวแปรบางตัวเท่านั้น
p "apple banana orange".split
$; = "-"
p "apple-banana-orange".split
numbers = ["one", "two", "three", "four"]
p numbers.join
$, = ", "
p numbers.join
ในตัวอย่างเป็นการใช้งานตัวแปร $; เป็นตัวแปรที่ใช้เก็บ String เพื่อใช้เป็นจุดตัดสำหรับเมธอด split และตัวแปร $, เป็นตัวแปรที่ใช้เก็บ String เพื่อเชื่อมอาเรย์ด้วยเมธอด joint
$; = "-"
p "apple-banana-orange".split
ในตอนแรก เราได้เรียกใช้งานเมธอด split เพื่อตัด String ออกจากกันและค่าที่ได้นั้นจะเป็นอาเรย์ของ String โดยเมธอดนี้จะใช้ค่าในตัวแปร $; เป็นตัวแบ่ง เราสามารถเปลี่ยนแปลงค่าในตัวแปรนี้ ถ้าหากเราต้องการใช้ค่าอื่นเป็นตัวแบ่ง
$, = ", "
p numbers.join
ต่อมาเป็นการใช้งานเมธอด join ซึ่งทำหน้าสำหรับเชื่อมอาเรย์ให้เป็น String โดยการเชื่อมนั้นจะใช้ String ที่กำหนดในตัวแปร $, ในการใช้งานเมธอด join นั้นคุณต้องตรวจสอบให้แน่ใจว่าตัวแปรทุกตัวในอาเรย์ที่ต้องการเชื่อมนั้นเป็น String หรือสามารถแปลงไปเป็น String อัตโนมัติด้วย Ruby ได้ ไม่เช่นนั้นจะเกิดข้อผิดพลาดขึ้น
["apple", "banana", "orange"]
["apple", "banana", "orange"]
"onetwothreefour"
"one, two, three, four"
นี่เป็นผลลัพธ์การทำงานของโปรแกรม
มาดูตัวอย่างอีกสักนิด ซึ่งจะเป็นตัวอย่างของตัวแปร global ที่ใช้งานกับ regular expression
s = "Let the peace of Christ rule in your hearts"
matched = s.match(/Christ/)
puts matched.inspect
puts "Pre-matched: #{matched.pre_match}"
puts "Matched text: #{matched}"
puts "Post-matched: #{matched.post_match}"
puts $~.inspect
puts "Pre-matched: #{$`}"
puts "Matched text: #{$&}"
puts "Post-matched: #{$'}"
ในตัวอย่าง เป็นการใช้งานเมธอด match จากตัวแปร String จะทำการค้นหาข้อความที่ตรงกับ pattern /Christ/ ที่ส่งเป็นพารามิเตอร์ของเมธอด โดยเมธอดจะส่งค่ากลับเป็นออบเจ็ค MatchData ที่เก็บรายละเอียดของการ match เอาไว้
puts matched.inspect
puts "Pre-matched: #{matched.pre_match}"
puts "Matched text: #{matched.to_s}"
puts "Post-matched: #{matched.post_match}"
ส่วนแรกของการแสดงผลนั้นเราใช้ข้อมูลจากตัวแปรออบเจ็ค matched ซึ่งจะประกอบไปด้วยข้อมูลของการ match ทั้งหมด เมธอด pre_match จะส่ง string ทางด้านซ้ายของการ match เมธอด post_match จะส่ง string ทางด้านขวาของการ match และเมธอด to_s เป็น string จากการ match
puts $~.inspect
puts "Pre-matched: #{$`}"
puts "Matched text: #{$&}"
puts "Post-matched: #{$'}"
นอกจากเมธอดจะส่งค่ากลับมาเป็นออบเจ็คของ MatchData แล้ว Ruby ยังนำข้อมูลเหล่านั้นเก็บไว้ในตัวแปร global ด้วย ตัวแปร $~ จะเก็บข้อมูลการ match ครั้งสุดท้ายในขอบเขตปัจจุบัน ตัวแปร $` จะเก็บ string ทางด้านซ้ายของการ match ที่สำเร็จครั้งสุดท้าย ตัวแปร $' จะเก็บ String ทางด้านขวาของการ match ที่สำเร็จครั้งสุดท้าย และตัวแปร $& จะเก็บ string ที่ match สำเร็จครั้งสุดท้าย
#<MatchData "Christ">
Pre-matched: Let the peace of
Matched text: Christ
post-matched: rule in your hearts
#<MatchData "Christ">
Pre-matched: Let the peace of
Matched text: Christ
post-matched: rule in your hearts
และนี่เป็นผลลัพธ์การทำงานของโปรแกรม
ในบทนี้ คุณได้เรียนรู้เกี่ยวกับขอบเขตของตัวแปร และประเภทของตัวแปรในภาษา Ruby และมันเพียงพอสำหรับการเขียนโปรแกรมในภาษา Ruby