ตัวดำเนินการ ในภาษา Ruby

ตัวดำเนินการ (Operators) คือสัญลักษณ์ที่ใช้บอกกับตัวแปรภาษาหรือคอมไพเลอร์เพื่อดำเนินการบางอย่างกับข้อมูลเพื่อให้ได้ผลลัพธ์ใหม่ออกมา เช่น การดำเนินการทางคณิตศาสตร์ การเปรียบเทียบค่าของข้อมูล หรือการดำเนินการทางตรรกศาสตร์ เป็นต้น ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับการใช้งานตัวดำเนินการประเภทต่างๆ ในภาษา Ruby และนี่เป็นเนื้อหาเกี่ยวกับตัวดำเนินการในบทเรียนนี้

  • Assignment operator
  • Arithmetic operators
  • Comparison operators
  • Logical operators
  • Bitwise operators
  • ลำดับความสำคัญของตัวดำเนินการ

Assignment operator

ตัวดำเนินการกำหนดค่า (Assignment operator) เป็นตัวดำเนินการที่แสดงโดยเครื่องหมายเท่ากับ (=) มันใช้สำหรับกำหนดค่าให้กับตัวแปร ค่าคงที่ หรือออบเจ็คต่างๆ ในภาษา Ruby ซึ่งโดยส่วนมากแล้วเรามักจะใช้ตัวดำเนินการกำหนดค่าแทบตลอดเวลา เช่น ในตอนที่เราประกาศตัวแปร หรือต้องการอัพเดทค่าในตัวแปร

a = 3
a = 5 + 2
lang = "Ruby"

ในตัวอย่าง เป็นการใช้งานตัวดำเนินการกำหนดค่าเพื่อกำหนดค่าให้กับตัวแปร ในโค้ดบรรทัดแรก เราได้ประกาศตัวแปร a โดยกำหนดค่าให้กับตัวแปรเป็น 2 หลังจากนั้นเปลี่ยนแปลงค่าในตัวแปรจากผลลัพธ์ของนิพจน์ 5 + 2 (เท่ากับ 7) และสุดท้ายเป็นการกำหนดค่า String "Ruby" ให้กับตัวแปร lang

ตัวดำเนินการกำหนดค่านั้นจะทำงานจากขวาไปซ้าย นั่นหมายความว่าค่าที่อยู่ทางขวา จะถูกคัดลอกไปใส่ไว้ในตัวแปรทางด้านซ้ายของตัวดำเนินการ ตามกฏของ right-to-left

a = b = c =2

ในตัวอย่าง เราได้ประกาศสามตัวแปรในคำสั่งเดียว โดยทุกตัวแปรมีค่าเป็น 2 ซึ่งมีหลักการทำงานดังนี้ 2 ถูกกำหนดให้กับตัวแปร c ค่าของตัวแปร c (ซึ่งก็คือ 2) ถูกกำหนดให้กับตัวแปร b และสุดท้ายค่าของตัวแปร b ก็ถูกกำหนดให้กับตัวแปร a

นอกจากนี้ ตัวดำเนินการกำหนดค่ายังใช้หนดค่าเริ่มต้นในพารามิเตอร์ของเมธอด ดังตัวอย่างต่อไปนี้

def say(message = "Hello")
    puts message
end

say()
say("Hi")

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Hello
Hi

ในตัวอย่าง เป็นการใช้ตัวดำเนินการกำหนดค่าเพื่อกำหนดค่าเริ่มต้นให้กับพารามิเตอร์ของเมธอด say นั่นทำให้คุณสามารถเรียกใช้งานเมธอดแบบมีหรือไม่มีพารามิเตอร์ก็ได้ ซึ่งถ้าหากไม่มีพารามิเตอร์ส่งมา เมธอดจะใช้ค่าเริ่มต้น "Hello" ในการแสดงผลแทน คุณจะได้เรียนรู้เกี่ยวกับเมธอดเพิ่มเติมในบทของเมธอด

Arithmetic operators

ตัวดำเนินการทางคณิตศาตร์ (Arithmetic operators) เป็นตัวดำเนินการที่ใช้สำหรับคำนวณหาค่าผลลัพธ์ในทางคณิตศาสตร์ที่เราคุ้ยเคยกัน เช่น การบวก การลบ การคูณ และการหาร แต่อย่างไรก็ตาม ในภาษา Ruby นั้นยังมีตัวดำเนินการทางคณิตศาตร์อื่นๆ ที่สามารถอำนวยความสะดวกให้เราในการเขียนโปรแกรม

นี่เป็นตารางของตัวดำเนินการทางคณิตศาสตร์ในภาษา Ruby

Operator Name Example
+ การบวก a + b
- การลบ a - b
* การคูณ a * b
+ การหาร a / b
% การหารเอาเศษ a % b
** การยกกำลัง a ** b

ตัวดำเนินการทางคณิตศาสตร์ที่คุณเห็นนั้นคุณน่าจะคุ้นเคยคือ แต่ตัวดำเนินการที่อาจจะใหม่สำหรับคุณก็คือตัวดำเนินการหารเอาเศษ (Modulo) (%) มันใช้สำหรับหาเศษที่เหลือจากการหารระหว่างสองตัวเลข

puts 11 % 3 # => 2

ในตัวอย่างนั้นผลลัพธ์ที่ได้จะมีค่าเท่ากับ 2 เนื่องจากตัวดำเนินการหารเอาเศษจะผลลัพธ์ที่ได้จะเป็นเศษของการหารที่เกิดจาก 11 / 3 เท่ากับ 3 เศษ 2 นั่นเอง

ต่อไปมาดูตัวอย่างการใช้งานตัวดำเนินการทางคณิตศาสตร์กัน แน่นอนว่าเมื่อคุณซื้อของ สิ่งหนึ่งที่คุณต้องจ่ายเพิ่มคือภาษีมูลค่าเพิ่มจากราคาของสินค้า เราจะเขียนโปรแกรมเพื่อคำนวณหาภาษีมูลค่าเพิ่มจากราคาของสินค้าที่ใส่เข้ามาในโปรแกรม นี่เป็นโค้ดของโปรแกรม

tax_percent = 7

print "Enter amount of subtotal: "
sub_total = gets.chomp.to_f

tax_amount = (sub_total * tax_percent) / 100
total = sub_total + tax_amount

puts "Subtotal: ฿ #{sub_total}"
puts "Tax (#{tax_percent}%): ฿ #{tax_amount}"
puts "Total: ฿ #{total}"

ในตัวอย่าง เป็นโปรแกรมสำหรับคำนวณหาภาษีอย่างง่ายที่คุณสามารเขียนได้ในภาษา Ruby โปรแกรมของจะรับค่าของราคาสิ้นค้าทั้งหมดที่ยังไม่รวมภาษีเข้ามา แล้วจะคำนวณหาภาษีมูลค่าเพิ่มและราคาทั้งหมดที่ต้องจ่าย และแสดงผลลัพธ์ออกทางหน้าจอ

tax_percent = 7

print "Enter amount of subtotal: "
sub_total = gets.chomp.to_f

ในตอนแรก เราได้กำหนดอัตราภาษีมูลค่าเพิ่มที่มีหน่วยเป็นเปอร์เซนต์ในตัวแปร tax_percent ซึ่งมันหมายความว่าถ้าหากคุณซื้อของในราคา 100 บาท คุณจะต้องจ่ายภาษีเป็นจำนวน 7 บาท หลังจากนั้นเรารับค่าของราคาของทั้งหมดเข้ามาเก็บไว้ในตัวแปร sub_total

tax_amount = (sub_total * tax_percent) / 100

คำสั่งต่อมาเป็นการคำนวณหาภาษีมูลค่าเพิ่ม ซึ่งมีสูตรการคำนวณคือนำราคาทั้งหมด คูณด้วยอัตรของภาษี แล้วนำไปหารด้วย 100 และนำค่าที่ได้เก็บในตัวแปร tax_amount สังเกตว่าเราสามารถใช้หลายตัวดำเนินการในคำสั่งเดียวได้ และใช้วงเล็บเพื่อจัดลำดับความสำคัญในการทำงาน

total = sub_total + tax_amount

หลังจากที่เราสามารถคำนวณหาภาษีมูลค่าเพิ่มได้แล้ว เรานำไปบวกกับราคาของสินค้าที่ยังไม่รวมภาษี ซึ่งเราจะได้ราคาทั้งหมดที่จะต้องจ่าย และเก็บไว้ในตัวแปร total

Enter amount of subtotal: 350
Subtotal: ฿ 350.0
Tax (7%): ฿ 24.5
Total: ฿ 374.5

นี่เป็นผลลัพธ์การทำงานของโปรแกรม เมื่อเรากรอกราคาเป็น 350 บาท ซึ่งในราคานี้จะมีภาษีที่ต้องจ่ายอยู่ที่ 24.5 บาท และราคาทั้งหมดที่ต้องจ่ายรวมภาษีสำหรับการซื้อของครั้งนี้คือ 374.5 บาท

Comparison operators

ตัวดำเนินการเปรียบเทียบ (Comparison operators) เป็นตัวดำเนินการที่ใช้เพื่อเปรียบเทียบค่าสองค่า และผลลัพธ์ที่ได้จากตัวดำเนินการเปรียบเทียบจะเป็น Boolean เสมอ (ซึ่งมีค่าเป็น true หรือ false) โดยส่วนมากแล้วค่าที่เป็น Boolean มักจะนำไปใช้กับคำสั่งเลือกเงื่อนไขและคำสั่งวนซ้ำ เพื่อควบคุมทิศทางการทำงานของโปรแกรม

นี่เป็นตารางของตัวดำเนินการเปรียบเทียบในภาษา Ruby

Operator Name Example
== เท่ากับ a == b
!= ไม่เท่ากับ a != b
< น้อยกว่า a < b
<= น้อยกว่าหรือเท่ากับ a <= b
> มากกว่า a > b
>= มากกว่าหรือเท่ากับ a >= b
<=> เปรียบเทียบสามทาง a <=> b

ตัวดำเนินการเปรียบเทียบใช้สำหรับเปรียบเทียบระหว่างค่าสองค่าที่อยู่ทางซ้ายและทางขวาของตัวดำเนินการ นิพจน์ a == b หมายถึงเป็นการเปรียบเทียบว่าค่าของ a เท่ากับค่าของ b หรือไม่ และในขณะเดียวกัน a > b เป็นการเทียบว่าค่าของ a มากกว่า b หรือไม่

puts 1 == 1         # => true
puts 2 != 3         # => true
puts 6 < 5          # => false
puts 8.0 <= 7.6     # => false
puts 3 + 1 > 10 / 2 # => false
puts (10 * 10) + 1 >= 101           # => true
puts 'A' == 'B'     # => false
puts "PHP" < "Ruby" # => true

ในตัวอย่าง เป็นการใช้ตัวดำเนินเปรียบเทียบเพื่อตรวจสอบค่าของข้อมูล แน่นอนว่าในภาษา Ruby การเปรียบเทียบตัวเลขนั้นตรงไปตรงมา ส่วนการเปรียบเทียบค่าที่เป็น String นั้นจะใช้หลักการเปรียบเทียบแบบการเรียงกันของคำในพจนานุกรม กล่าวคือ "A" จะน้อยกว่า "B" เนื่องจากตัวอักษร "A" มาก่อนในพจนานุกรม

puts 3 + 1 > 10 / 2 # => false

นอกจากนี้ เรายังสามารถใช้ตัวดำเนินการเปรียบเทียบร่วมกับตัวดำเนินการทางคณิตศาสตร์ได้ ในตัวอย่างด้านบน โปรแกรมจะทำงานเพื่อหาผลลัพธ์ของตัวดำเนินการทางคณิตศาสตร์ก่อน แล้วค่อยนำค่าทั้งสองด้านมาเปรียบเทียบกัน ที่เป็นเช่นนี้ก็เพราะว่าตัวดำเนินการทางคณิตศาสตร์นั้นมีลำดับความสำคัญมากกว่าตัวดำเนินการเปรียบเทียบนั่นเอง ดังนั้นในตัวอย่างด้านบน เราสามารถเขียนได้เป็น

puts (3 + 1) > (10 / 2) # => false
# หรือ
a = 3 + 1
b = 10 /2
puts a > b # => false

ตัวดำเนินการเปรียบเทียบสามทาง (<=>) เป็นตัวดำเนินการนี้ใช้เปรียบเทียบระหว่างค่าสองค่าเช่นเดียวกัน แต่ผลลัพธ์ที่ได้จะไม่ใช่ Boolean แต่เป็น Integer แทน ดังนั้นในนิพจน์ a <=> b นั้นหมายความว่าถ้าหาก a มีค่าน้อยกว่า b ผลลัพธ์ที่ได้จะเป็น -1 ถ้าหาก a มีค่าเท่ากับ b ผลลัพธ์ที่ได้จะเป็น 0 และถ้าหาก a มีค่ามากกว่า b ผลลัพธ์ที่ได้จะเป็น 1

นี่เป็นตัวอย่างของตัวดำเนินการเปรียบเทียบสามทาง

puts 1 <=> 2        # => -1
puts 5 <=> 5.0      # => 0
puts 'C' <=> 'A'    # => 1

หลังจากที่คุณรู้จักตัวดำเนินการเปรียบเทียบทั้งหมดแล้ว ต่อไปมาดูตัวอย่างของการใช้งานตัวดำเนินการเหล่านี้กัน สมมติว่าเราสร้างเกมขึ้นมาและต้องการจำกัดอายุให้คนที่มีอายุตั้งแต่ 13 ปีขึ้นไปเท่านั้นที่สามารถเล่นได้ นี่เป็นโปรแกรมของเรา

print "Enter your age: "
age = gets.chomp.to_i

if age >= 13
    puts "You can play this game"
else
    puts "Sorry"
end

ในตัวอย่างเป็นโปรแกรมสำหรับตรวจสอบอายุของผู้เล่น โดยโปรแกรมจะถามให้ผู้เล่นใส่อายุของตนเองผ่านทางคีย์บอร์ด และเก็บไว้ในตัวแปร age

if age >= 13

หลังจากนั้นเราใช้ตัวดำเนินการมากกว่า (>=) เพื่อเปรียบเทียบอายุว่ามากกว่าหรือเท่ากับ 13 ปีหรือไม่ ถ้าหากใช่โปรแกรมจะทำงานในบล็อคของคำสั่ง if และถ้าหากไม่ใช่โปรแกรมจะทำงานในบล็อคของคำสั่ง else แทน ซึ่งในแต่ละบล็อคจะแสดงข้อความบอกว่าสามารถเล่นเกมได้หรือไม่

Enter your age: 20
You can play this game

นี่เป็นผลลัพธ์การทำงานของโปรแกรมเมื่อกรอกอายุเป็น 20 คุณสามารถลองกรอกอายุที่ทำให้เงื่อนไขไม่เป็นจริง และดูผลลัพธ์ว่าโปรแกรมทำงานอย่างไร

ผลลัพธ์จากตัวดำเนินการเปรียบเทียบนั้นเป็นค่าของ Boolean (true และ false) ที่สามารถใช้ได้กับคำสั่งเลือกเงื่อนไข if เพื่อควบคุมการทำงานของโปรแกรม ซึ่งคุณจะได้เรียนรู้เกี่ยวกับคำสั่งดังกล่าวอย่างละเอียดอีกครั้งในบทต่อไป

Logical operators

ตัวดำเนินการทางตรรกศาสตร์ (Logical operators) ในทางคอมพิวเตอร์นั้น เป็นตัวดำเนินการที่ใช้สำหรับเชื่อมต่อเครื่องหมายหรือนิพจน์เข้าด้วยกัน โดยทั่วไปแล้วตัวดำเนินการชนิดนี้จะใช้เชื่อมต่อ Boolean สองตัวเข้าด้วยกันด้วยวิธีการของประพจน์ในทางตรรกศาสตร์ และผลลัพธ์ที่ได้จะเป็นค่าของ Boolean เสมอ

นี่เป็นตารางของตัวดำเนินการทางตรรกศาสตร์ในภาษา Ruby

Operator Name Example
&& And a && b
|| Or a || b
! Not !a
and And a and b
or Or a or b
not Not not a

จากในตาราง จะเห็นว่ามีเพียงสามชื่อเท่านั้นที่แตกต่างกันคือ And Or และ Not ในภาษา Ruby มีตัวดำเนินการทางตรรกศาสตร์อยู่สองแบบคือ แบบสัญลักษณ์และแบบคำ ทั้งสองแบบนั้นมีการทำงานเหมือนกันในทางตรรกศาสตร์ แต่สิ่งที่แตกต่างกันคือตัวดำเนินการแบบคำจะมีลำดับความสำคัญน้อยกว่าแบบสัญลักษณ์

ตัวดำเนินการทางตรรกศาสตร์นั้นทำงานกับ Boolean และได้ผลลัพธ์เป็น Boolean ตัวดำเนินการ And นั้นจะได้ผลลัพธ์เป็น true เมื่อค่าทั้งสองเป็น true ไม่เช่นนั้นจะได้ค่าเป็น false ส่วนตัวดำเนินการ Or นั้นจะได้ผลลัพธ์เป็น true ถ้าหากมีอย่างน้อยหนึ่งค่าที่เป็น true ไม่เช่นนั้นจะได้ค่าเป็น false

สำหรับตัวดำเนินการ Not จะกลับค่านิพจน์จาก true เป็น false และจาก false เป็น true

ตารางค่าความจริงของตัวดำเนินการ And

A B Result
true true true
true false false
false true false
false false false

ตารางค่าความจริงของตัวดำเนินการ Or

A B Result
true true true
true false true
false true true
false false true

ตารางค่าความจริงของตัวดำเนินการ Not

A Result
true false
false true

ต่อไปเป็นตัวอย่างการใช้งานตัวดำเนินการตรรกศาสตร์ทั้งสามแบบ

puts true && true       # => true
puts false || true      # => true
puts true && 5 < 3      # => false, because (5 < 3) is false
puts 1 + 1 == 2 || 10 > 9 # => true, because (1 + 1 == 2) is true

puts !true              # => false
puts !false             # => true
puts !(4 == 5)          # => true, because (4 == 5) is false 

ในตัวอย่าง เป็นการใช้งานตัวดำเนินการตรรกศาสตร์เพื่อรวมนิพจน์ Boolean สองค่าที่อยู่ทางซ้ายและทางขวาของตัวดำเนินการให้เป็นค่าเดียว สังเกตว่าคุณสามารถใช้ค่า Boolean โดยตรงหรือนิพจน์ที่สร้างมาจากตัวดำเนินการเปรียบเทียบได้ เราสามารถทำเช่นนี้ได้เนื่องจากตัวดำเนินการเปรียบเทียบมีลำดับความสำคัญมากกว่าตัวดำเนินการตรรกศาสตร์

อย่างไรก็ตาม ตัวดำเนินการ Not ทั้งสองแบบนั้นมีลำดับความสำคัญที่แตกต่างกัน ตัวดำเนินการ ! มีลำดับความสำคัญมากกว่าตัวดำเนินการตัวดำเนินการทางคณิตศาสตร์และตัวดำเนินการเปรียบเทียบ ในขณะที่ตัวดำเนินการ Not (not) มีลำดับความสำคัญน้อยกว่า ลองพิจารณาตัวอย่างต่อไปนี้

puts (! true == true)       # => false
puts (not true == false)    # => true

จากตัวอย่างด้านบนคำสั่งแรกถูกประมวลผลเป็น (! true) == true และในคำสั่งที่สองถูกประมวลผลเป็น not (true == false) เนื่องจากว่าลำดับความสำคัญของตัวดำเนินการ Not ทั้งสองไม่เท่ากัน ดังนั้นถ้าหากคุณต้องการให้โปรแกรมทำงานในตัวดำเนินการเปรียบเทียบก่อน มันจะต้องถูกเขียนเป็น

puts (! (true == true))       # => false
puts (not (true == false))    # => true

หลังจากที่ได้รู้จักกับตัวดำเนินการทางตรรกศาสตร์ทั้งหมดแล้ว มาดูตัวอย่างในการนำไปประยุกต์ใช้เพื่อเขียนโปรแกรมกัน

money = 50000
age = 18

if money >= 30000 && age >= 20
    puts "You can buy this house" 
else
    puts "Sorry! you cannot buy it right now"
end

โปรแกรมแรกนั้นเป็นโปรแกรมคำนวณว่าคุณสามารถที่จะซื้อบ้านได้หรือไม่ โดยเงื่อนไขในการซื้อบ้านนั้นมีอยู่ว่าคุณต้องมีเงินมากกว่าหรือเท่ากับ 30000 ซึ่งเป็นราคาของบ้าน และมีอายุตั้งแต่ 20 ปีขึ้นไป เราได้เก็บค่านำเข้าทั้งสองไว้ในตัวแปร money และ age คุณสามารถปรับโปรแกรมให้รับค่าจากคีย์บอร์ดได้

if money >= 30000 && age >= 20

ต่อมาเป็นการตรวจสอบเงื่อนไขด้วยคำสั่ง if ซึ่งเป็นการตรวจสอบว่าถ้าหากมีเงินมากกว่าหรือเท่ากับ 30000 และมีอายุตั้งแต่ 20 ปีขึ้นไป จะสามารถซื้อบ้านหลังนี้ได้ นั่นหมายความว่าถ้าหากเงื่อนไขใดเงื่อนไขหนึ่งไม่เป็นจริง ผลลัพธ์ที่ได้จากการตรวจสอบเงื่อนไขจะเป็น false และโปรแกรมทำงานในบล็อคของคำสั่ง else แทน

Sorry! you cannot buy it right now

และนี่เป็นผลลัพธ์การทำงานของโปรแกรม เนื่องจากว่าอายุยังไม่ถึง ดังนั้นจึงไม่สามารถซื้อบ้านได้แม้เงินจะเพียงพอก็ตาม ในตอนนี้ให้คุณลองเปลี่ยนอายุให้มากขึ้นเพื่อให้สามารถซื้อบ้านได้

ต่อไปมาดูอีกหนึ่งตัวอย่างสำหรับการใช้งานตัวดำเนินการทางตรรกศาสตร์ สมมติว่าเราได้พัฒาเกมขึ้นมา เราจะเขียนคำสั่งเพื่อตรวจสอบเงื่อนไขในเกมของเราว่าตัวละครจะได้รับดาบศักดิ์สิทธิ์นี้ไปครอบครองหรือไม่ นี่เป็นโค้ดของโปรแกรม

name = "Mateo"
num_of_items = 19
gold = 1200
level = 60

if (level >= 50 || gold >= 1000) && num_of_items < 20
    puts "#{name}, you've got a sword"
    num_of_items = num_of_items + 1
    gold -= 1000 if level < 50
else
    puts "Sorry #{name}! you cannot get it"
end

puts "Now your gold: #{gold}"
puts "Item in inventory: #{num_of_items}"

ในตัวอย่าง ตัวละครในเกมของเรามีการเก็บค่าสามอย่างคือจำนวนไอเท็มที่มี num_of_items จำนวนเงินที่มี gold และเลเวลของตัวละคร level ในกรณีนี้ เราได้กำหนดค่าเริ่มต้นให้กับทั้งสามตัวแปรดังกล่าว ซึ่งในทางปฎิบัติแล้วค่าเหล่านี้ควรคำนวณมากจากในตอนที่ผู้เล่นกำลังเล่นเกม

if (level >= 50 || gold >= 1000) && num_of_items < 20

ในการที่จะได้รับดาบนั้นผู้เล่นจะได้รับดาบฟรีถ้าหากเขามีเลเวลตั้งแต่ 50 ขึ้นไป หรือเขาสามารถซื้อด้วยทองคำเป็นจำนวน 1000 ทองได้ แต่อย่างไรก็ตาม ถึงแม้เงื่อนไขทั้งสองอย่างจะเป็นจริง เขาจะต้องมีช่องเก็บของเพียงพอในการเก็บดาบด้วย ซึ่งช่องเก็บของนั้นสามารถเก็บได้มากที่สุด 20 ชิ้น

num_of_items = num_of_items + 1
gold -= 1000 if level < 50

และถ้าหากว่าเขาสามารถได้รับดาบ โปรแกรมจะแสดงผลบอกว่าคุณได้รับดาบและจะบวกเพิ่มจำนวนของเพิ่มขึ้นไปหนึ่ง นอกจากนี้เรายังทำการลดเงินของเขาลง ถ้าหากว่าเขาเลเวลไม่ถึง 50

Mateo, you've got a sword
Now your gold: 1200
Item in inventory: 20

นี่เป็นผลลัพธ์การทำงานของโปรแกรม คุณสามารถเปลี่ยนแปลงค่าในตัวแปรและตรวจสอบการทำงานของโปรแกรมว่าได้ผลลัพธ์ตามที่คุณคาดหวังไว้หรือไม่

Bitwise operators

ตัวดำเนินการระดับบิต (Bitwise operators) เป็นตัวดำเนินที่ใช้แก้ไขและเปลี่ยนแปลงค่าหรือตัวแปรที่เก็บข้อมูลในระดับบิตหรือในรูปแบบของตัวเลขฐานสองของข้อมูล มันเป็นการทำงานที่เรียบง่ายและรวดเร็ว นี่เป็นตารางของตัวดำเนินการระดับบิตในภาษา Ruby

Operator Name Description Exmaple
& AND Bitwise AND a & b
| OR Bitwise Inclusive OR a | b
^ XOR Bitwise Exclusive OR a ^ b
~ NOT Bit inversion ~a
<< SHIFT LEFT Shift Left a << offset
>> SHIFT RIGHT Shift Right a >> offset

ตัวดำเนินการระดับบิต AND, OR, XOR จะทำการเปรียบเทียบบิตทีละตำแหน่งจากข้อมูลทั้งสองชุด โดยบิตนั้นจะแสดงอยู่ในเลขฐานสองที่มีเพียง 1 และ 0 เท่านั้น ซึ่งการทำงานนั้นจะคล้ายกับตัวดำเนินการตรรกศาสตร์ นี่เป็นตารางค่าความจริงของตัวตัวดำเนินการประเภทต่างๆ

ตารางค่าความจริงของตัวดำเนินการระดับบิต AND

ตัวดำเนินการระดับบิต AND จะให้ผลลัพธ์เป็น 1 ถ้าหากบิตทั้งสองมีค่าเป็น 1 ไม่เช่นนั้นจะได้ผลลัพธ์เป็น 0

บิต A บิต B บิตผลลัพธ์
1 1 1
1 0 0
0 1 0
0 0 0

ตารางค่าความจริงของตัวดำเนินการระดับบิต OR

ตัวดำเนินการระดับบิต OR จะให้ผลลัพธ์เป็น 1 ถ้าหากมีอย่างน้อยหนึ่งบิตที่เป็น 1 ไม่เช่นนั้นจะได้ผลลัพธ์เป็น 0

บิต A บิต B บิตผลลัพธ์
1 1 1
1 0 1
0 1 1
0 0 0

ตารางค่าความจริงของตัวดำเนินการระดับบิต XOR

ตัวดำเนินการระดับบิต XOR จะให้ผลลัพธ์เป็น 1 ถ้าหากบิตทั้งสองมีค่าที่แตกต่างกัน

บิต A บิต B บิตผลลัพธ์
1 1 1
1 0 1
0 1 1
0 0 0

ตารางค่าความจริงของตัวดำเนินการระดับบิต NOT

ตัวดำเนินการระดับบิต NOT ทำการกลับบิตเป็นค่าที่ตรงกันข้าม

บิต A บิตผลลัพธ์
1 0
0 1

นี่เป็นตัวอย่างสำหรับการใช้งานตัวดำเนินการระดับบิต

a = 5   # 0101
b = 14  # 1110
puts a & b # 0100
puts a | b # 1111
puts a ^ b # 1011
puts ~a    # ..1010

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

4
15
11
-6

ในตัวอย่าง เมื่อเรากำหนดค่าให้กับตัวแปรในรูปแบบเลขฐานสิบ ในกรณีนี้คือ 5 และ 14 ตัวแปรภาษาแปลงตัวเลขดังกล่าวและเก็บมันในรูปแบบของตัวเลขฐานสองในหน่วยความจำ ในที่นี้คือ 0101 ตามลำดับ 1110 ดังนั้นเมื่อเราใช้ตัวดำเนินการระดับบิตกับตัวแปรเหล่านั้น มันดำเนินการกับบิตของข้อมูลโดยตรง

ในความเป็นจริงแล้วตัวเลข 5 และ 14 นั้นเป็นเพียง Literal ของตัวเลขในรูปแบบของเลขฐานสิบเท่านั้น ในภาษา Ruby คุณสามารถกำหนดค่า Literal ของตัวเลขในรูปแบบของเลขฐานสองได้ ดังนั้นสองตัวแปรนี้ให้ผลลัพธ์ที่เหมือนกับ มันมีค่าเท่ากับ 5

a = 0b101
b = 5
puts a == b # => true

และอย่างที่คุณเห็น เมธอด puts นั้นสามารถใช้แสดงตัวเลขในฐานสิบได้เท่านั้น ถ้าหากคุณต้องการแสดงในฐานอื่นๆ คุณต้องใช้เมธอด printf เพื่อจัดรูปแบบการแสดงผลแทน

a = 5
b = 14
printf "EXP\tBIN\tDEC\n"
printf "a\t%04b\t%d\n", a, a
printf "b\t%04b\t%d\n", b, b
printf "a & b\t%04b\t%d\n", a & b, a & b
printf "a | b\t%04b\t%d\n", a | b, a | b
printf "a ^ b\t%04b\t%d\n", a ^ b, a ^ b
printf "~a\t%04b\t%d\n", ~a, ~a

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

EXP     BIN     DEC
a       0101    5
b       1110    14
a & b   0100    4
a | b   1111    15
a ^ b   1011    11
~a      ..1010  -6

ในตัวอย่าง เป็นการใช้งานเมธอด printf ในการจัดรูปแบบการแสดงผล เพื่อให้คุณเห็นว่าค่าในเลขฐานสองที่แท้จริงของข้อมูลนั้นเป็นอย่างไร

ต่อไปเป็นตัวอย่างการใช้งานตัวดำเนินการ Bitwise Shift Left และ Bitwise Shift Right เพื่อใช้สำหรับเลื่อนบิตไปทางซ้ายหรือทางขวา

a = 20 # bit stored 10100

puts a >> 1 # 01010 equal to 10
puts a >> 2 # 00101 equal to 5

puts a << 1 # 101000 equal to 40
puts a << 2 # 1010000 equal to 80

ในตัวอย่างเราประกาศตัวแปร a และกำหนดค่าให้กับตัวแปรเป็น 20 ค่า และดังกล่างถูกตัวแปรภาษาแปลงค่าเป็น 10100 และเก็บไว้ในหน่วยความจำ เนื่องจากว่าคอมพิวเตอร์สามารถเข้าใจเพียงเลขฐานสอง สังเกตในคอมเมนต์ที่ด้านขวาของคำสั่งโปรแกรม

puts a >> 1 # 01010 equal to 10
puts a >> 2 # 00101 equal to 5

ในนิพจน์ a >> 1 เป็นการเลื่อนบิตของ a ไปทางด้านขวาหนึ่งตำแหน่ง และนิพจน์ a >> 2 เป็นการเลื่อนบิตของ a ไปทางด้านขวาสองตำแหน่ง ในการเลื่อนบิตแต่ละครั้งบิตในตำแหน่งขวาสุดจะหายไปตามจำนวนที่เลื่อน

puts a << 1 # 101000 equal to 40
puts a << 2 # 1010000 equal to 80

สำหรับการเลื่อนบิตไปทางซ้ายนั้น บิต 0 จะถูกเพิ่มเข้ามาจากทางด้านขวาตามจำนวนที่เลื่อนไป และจากการเลื่อนบิตไปทั้งทางซ้ายและขวานั้นจะสังเกตได้ว่า เมื่อเราเลื่อนบิตไปทางซ้ายจะทำให้ตัวเลขเพิ่มขึ้นเป็นสองเท่า ในขณะที่การเลื่อนบิตทางซ้ายจะทำให้ตัวเลขลดลงครึ่งหนึ่ง

โดยทั่วไปแล้ว ตัวดำเนินการระดับบิตมักจะใช้สำหรับจัดการข้อมูลในระดับต่ำ (low-level) ซึ่งโดยส่วนใหญ่แล้วภาษาที่ใช้คุณสมบัตินี้จะเป็นภาษาอย่างภาษา C และ C++ แต่อย่างไรก็ตาม ถึงแม้ Ruby จะเป็นภาษาระดับสูง แต่มันก็ยังสนับสนุนการใช้งานตัวดำเนินการระดับบิตในกรณีที่คุณต้องการใช้มัน

ลำดับความสำคัญของตัวดำเนินการ

ลำดับความสำคัญของตัวดำเนินการ (Operator precedence) นั้นเป็นสิ่งที่ใช้กำหนดว่าโปรแกรมควรทำอะไรก่อน-หลัง ตัวดำเนินการที่มีลำดับความสำคัญสูงกว่า จะกลายมาเป็น Operand ของตัวดำเนินการที่มีลำดับความสำคัญต่ำกว่า

นี่เป็นตารางแสดงลำดับความสำคัญของตัวดำเนินการในภาษา Ruby เรียงจากตัวดำเนินการที่มีความสำคัญมากที่สุดไปยังน้อยที่สุด

ลำดับ ตัวดำเนินการ คำอธิบาย
0 () Grouping
1 !, ~, + Unary
2 ** Power
3 - Unary
4 *, /, % Multiplicative
5 +, - Additive
6 <<, >> Bit Shifting
7 & Bitwise AND
8 |, ^ Bitwise OR, Bitwise XOR
9 >, >=, <, <= Relational
10 <=>, ==, ===, !=, =~, !~ Equality
11 && Logical And
12 || Logical Or
13 .., ... Range
14 ?, : Ternary
15 rescue Block
16 =, +=, -=, *=, /= Assignment
17 defined? Method
18 not Not
19 or, and Logical Or, Logical And
20 if, unless, while, until Modifiers
21 { } Blocks

จากตารางด้านบน ตัวดำเนินการที่มีความสำคัญสูงที่สุดคือตัวดำเนินการในกลุ่ม Unary อย่างไรก็ตาม ถ้าหากเราครอบนิพจน์ใดๆ ด้วยวงเล็บ () โปรแกรมจะทำงานในวงเล็บก่อนเสมอ ในตอนนี้ มาดูที่คำสั่งต่อไปนี้

puts 1 + 3 * 5

จากตัวอย่างด้านบน คำตอบของคำโค้ดบรรทัดนี้คืออะไร 20 หรือ 16 และอย่างที่คุณได้คิดเอาไว้ คำตอบของนิพจนน์คือ 16 เนื่องจากตัวดำเนินการคูณ (*) นั้นมีลำดับความสำคัญมากกว่าตัวดำเนินการบวก (+) ดังนั้นมันจึงถูกประมวลผลเป็น 1 + (3 + 5)

ดังนั้นถ้าหากคุณต้องการให้ตัวเลขบวกกันก่อน คุณจะเป็นต้องใส่วงเล็บให้กับมันดังนี้

puts (1 + 3) * 5

อย่างไรก็ตาม เราแนะนำให้คุณใส่วงเล็บเสมอถ้าหากคุณใช้ตัวดำเนินการรวมกันเป็นจำนวนมาก นั่นจะทำให้โปรแกรมของคุณง่ายและสามารถเข้าใจได้ง่ายโดยคนอื่นๆ และคุณเอง

ในบทนี้ คุณได้เรียนรู้เกี่ยวกับตัวดำเนินการในภาษา Ruby และทราบว่าจะนำตัวดำเนินการประเภทต่างๆ นั้นไปใช้ในการเขียนโปรแกรมได้อย่างไร นอกจากนี้ คุณยังได้ทราบแล้วว่าลำดับความสำคัญของตัวดำเนินการนั้นเป็นสิ่งที่กำหนดว่าจะทำอะไรก่อนหลัง