วันอังคารที่ 28 กุมภาพันธ์ พ.ศ. 2560

เรียนรู้การใช้ภาษา Lua

เรียนรู้การใช้ภาษา Lua

บทความนี้กล่าวถึง ภาษา Lua ซึ่งเป็นภาษาคอมพิวเตอร์ และเรียนรู้การเขียนโค้ดในภาษานี้ โดยอาศัยโค้ดตัวอย่าง ผู้อ่านควรมีพื้นฐานการเขียนโปรแกรมมาบ้างเพื่อทำความเข้าใจเนื้อหาในบทความนี้
คำสำคัญ / Keywords: Lua programming language
ภาษา Lua (pronounced 'LOO-ah' หรือออกเสียงว่า 'ลัว' หรือ 'ลูอ่า' ในภาษาโปรตุเกส) อาจไม่เป็นที่รู้จักสำหรับโปรแกรมเมอร์ทั่วไปในวงกว้าง แต่ก็เป็นภาษาคอมพิวเตอร์ที่น่าสนใจ และสามารถนำมาใช้งานได้ ลองมาทำความรู้จักกับภาษานี้ โดยเขียนสรุปเป็นข้อๆ ดังนี้
  • Lua เป็นภาษาประเภท Scripting / Interpreted Language หรือภาษาสคริปต์ (อยู่ในประเภทเดียวกับภาษาอย่างเช่น Python)
  • มีต้นกำเนิดมาจากทีมพัฒนาในสถาบันการศึกษาแห่งหนึ่งในประเทศบราซิล (Pontifical Catholic University of Rio de Janeiro, Brazil) ในราวปีค.ศ. 1993
  • Lua script จะถูกแปลงให้เป็น Bytecode ตามรูปแบบคำสั่งของคอมพิวเตอร์เสมือน (Virtual Machine) สำหรับภาษานี้ (เช่นเดียวกับกรณีของ Python และ Java ที่มีการทำงานในลักษณะนี้)
  • เป็นภาษาที่ชนิดของข้อมูลสำหรับตัวแปรปรับเปลี่ยนได้ (Dynamically-typed language)
  • มีชนิดข้อมูลพื้นฐานคือ boolean (true,false), numbers (integer & double-precision floating point) และ string
  • มีโครงสร้างข้อมูล อย่างเช่น อาร์เรย์ (array) ตาราง (table) ซึ่งเป็น associative array และ เซต (set)
  • มีการจัดการหน่วยความจำ เช่น การจองและคืนหน่วยความจำในขณะทำงาน (automatic memory management & garbage collection)
  • ตัวแปลคำสั่งของภาษา Lua (Lua Interpreter) มีขนาดเล็ก (small & light-weight) และเขียนด้วยภาษา C
  • เป็นซอฟต์แวร์ประเภท Opensource (MIT license สำหรับเวอร์ชัน 5.x) ดังนั้นจึงใช้งานได้ฟรี
  • ใช้ได้หลายแพลตฟอร์ม (multi-platform programming language) อย่างเช่น Windows, Linux, Mac OS X
  • มีการใช้งานกับบอร์ดไมโครโทรลเลอร์ได้ อย่างเช่น ESP8266/NodeMCU, WiFiMCU/EMW3165 เป็นต้น
  • สามารถเรียกใช้จากภาษาอื่นได้ (embeddable) มีการนำไปใช้ในการพัฒนาเกมส์ หรือการพัฒนา Mobile Apps อย่างเช่น Corona SDK
  • อุปกรณ์เครือข่าย อย่างเช่น Wireless Router ที่ใช้ระบบปฏิบัติการ OpenWrt ซึ่งเป็น Linux และมีการใช้โปรแกรม Luci ซึ่งพัฒนาด้วยภาษา Lua สำหรับการจัดการผ่านหน้าเว็บเพื่อตั้งค่าต่างๆ ของระบบ (Web configuration interface)

โปรแกรมสำหรับการเขียนโค้ดในภาษา Lua

โปรแกรมที่ใช้ในการเขียนโค้ดภาษา Lua ได้แก่ 1) ตัวแปลคำสั่ง หรือ 'อินเทอร์พรีเตอร์' สำหรับภาษา Lua (Lua Interpreter) และ 2) โปรแกรมที่ใช้ในการเขียนโค้ดหรือ Code Editor ซึ่งมีให้เลือกใช้หลายตัวและเป็นซอฟต์แวร์ประเภท Opensource หรือติดตั้งใช้งานได้ฟรี
สำหรับโปรแกรม Lua Interpreter (binaries) สามารถหาดาวน์โหลดได้จาก sourceforge.net และผู้ใช้ระบบปฏิบัติการ Windows ให้เลือกไฟล์ lua-5.3.2_Win32_bin.zip หรือ lua-5.3.2_Win64_bin.zip (เวอร์ชันปัจจุบันคือ 5.3.2 ในขณะที่เขียนเอกสารนี้) ขึ้นอยู่กับว่าใช้ระบบปฏิบัติการแบบ 32 บิต หรือ 64 บิต ส่วนการติดตั้งใช้งาน ก็เพียงแตกไฟล์ (Unzip) แล้วนำไปใส่ในไดเรคทรอรี่ที่ต้องการ
สำหรับโปรแกรมที่ใช้ในการเขียนโค้ด ได้เลือกใช้โปรแกรม Sublime Text 2 และใช้ระบบปฏิบัติการ Windows เป็นตัวอย่าง โปรแกรมนี้รองรับการทำ Syntax Highlighting สำหรับภาษา Lua และอีกหลายภาษา


รูปหน้าต่างหลักของโปรแกรม Sublime Text 2 ที่นำมาใช้เขียนโค้ด Lua
สามารถแสดงสีไฮไลท์ (color highlighting) ของคำตามไวยากรณ์ภาษา Lua
สามารถ Build เพื่อทำคำสั่งโดยใช้ตัวแปลคำสั่งภาษา Lua ได้


การเรียนรู้ Lua จากตัวอย่าง / Learning Lua by Examples

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

หัวข้อในการเรียนรู้ภาษา Lua ขั้นพื้นฐานได้แก่
  • การเขียนคำอธิบายโค้ด (Code Comment)
  • การใช้คำสั่งแสดงข้อความเป็นเอาต์พุตหรือรับจากอินพุตของโปรแกรม (Standard I/O)
  • การประกาศใช้งานตัวแปร (Variable Declaration)
  • คำสงวนในภาษา Lua (Reserved Words)
  • ชนิดข้อมูลพื้นฐาน (Built-in Data Types)
  • ชนิดข้อมูลที่เป็นตัวเลข (Numbers)
  • ชนิดข้อมูลที่เป็นข้อความ (Strings)
  • การเขียนนิพจน์และโอเปเรเตอร์พื้นฐาน (Expressions & Operators)
  • ประโยคที่ทำงานตามเงื่อนไข (Conditional Statements)
  • ประโยคสำหรับการทำขั้นตอนซ้ำ (Loop Statements)
  • ความแตกต่างระหว่างตัวแปรภายนอกและภายใน (Global & Local Variables)
  • การสร้างฟังก์ชัน (Function Declarations)
  • การใช้งานโครงสร้างข้อมูลแบบอาร์เรย์ (Array-based Data Structures)
  • การใช้งานโครงสร้างข้อมูลแบบ Associative Array
  • การใช้งานตัวแปรที่เก็บข้อมูลแบบ String
  • การใช้ฟังก์ชันจากไลบรารี่ string ของ Lua

รูปแบบการเขียนโค้ดภาษา Lua

โดยทั่วไป บรรทัดแรกของไฟล์ชุดคำสั่งหรือสคริปต์ (script) ในภาษา Lua จะมีการระบุว่า จะใช้โปรแกรมใดที่ทำหน้าที่เป็น Lua Interpreter เช่น #!/usr/bin/env lua เพื่อใช้ทำตามประโยคคำสั่งต่างๆ ในสคริปต์ และมักใช้กับระบบปฏิบัติการอย่างเช่น Linux และเรียกใช้สคริปต์ผ่านหน้าต่างคอนโซล (console) ประโยคคำสั่งอาจมีความยาวหนึ่งบรรทัดหรือมากกว่าหนึ่งบรรทัดได้ ถ้าในบรรทัดเดียวกันมีประโยคคำสั่งมากกว่าหนึ่ง จำเป็นต้องมีสัญลักษณ์ semicolon (;) ปิดท้ายประโยคแต่ละประโยค

คำอธิบายโค้ด (code comment)

ในภาษา Lua การเขียนคำอธิบายในโค้ด (code comment) หรือโค้ดคอมเมนต์ ถ้าเขียนแบบบรรทัดเดียว (single-Line comment) จะเริ่มต้นด้วยสัญลักษณ์ -- (double-dash หรือ double hyphen) และข้อความที่ตามมาในบรรทัดนั้นให้ถือว่าเป็นโค้ดคอมเมนต์ แต่ถ้าจะเขียนมากกว่าหนึ่งบรรทัด (multiple-line comment) ให้เขียนอยู่ระหว่าง --[[ และ --]]

การแสดงข้อความออกทางช่องเอาต์พุตของโปรแกรม

คำสั่งที่ใช้ในการแสดงข้อความ (string) หรือข้อมูลชนิดอื่นๆ ให้เป็นข้อความทางช่อง เอาต์พุตของโปรแกรม คือ print() หรือใช้คำสั่ง io.write() โดยระบุอาร์กิวเมนต์ (arguments) ป้อนให้คำสั่งเหล่านี้ ถ้ามีข้อความหรือตัวแปรมากกว่าหนึ่ง ก็เขียนอาร์กิวเมนต์แยกด้วยเครื่องหมาย comma (,) คำสั่ง print() เมื่อแสดงข้อความแล้วจะขึ้นบรรทัดใหม่ (newline) โดยอัตโนมัติซึ่งแตกต่างจากคำสั่ง io.write()

ชนิดข้อมูลที่เป็นข้อความ (String Data Type)

ในภาษา Lua ข้อความ (string) จะเริ่มต้นและจบท้ายด้วย ' ... ' (single qoutes) หรือ " ... " (double quotes) ถ้าจะนำข้อความมาต่อกัน (string concatenation) ก็ใช้โอเปเรเตอร์ .. (double dots) จะได้เป็นข้อความใหม่ (new string object) ข้อความเมื่อถูกสร้างขึ้นมาแล้วและถูกอ้างอิงด้วยตัวแปร จะไม่สามารถเปลี่ยนแปลงข้อมูลภายในได้ (immutable string) ข้อความอาจมีตัวอักขระที่เรียกว่า Escape Character ซึ่งเริ่มต้นด้วยสัญลักษณ์ Backslash (\)
ตัวอย่าง Escape Characters
  • \t หมายถึง การเว้นช่องว่างหรือ Tab,
  • \n หมายถึง การขึ้นบรรทัดใหม่ (newline)
  • \\ หมายถึง สัญลักษณ์ Backslash (\)
  • \" หมายถึง สัญลักษณ์ Double Qoute (")
  • \xhh หมายถึง ตัวอักขระหนึ่งตัวตามรหัส ASCII โดยที่ hh ใช้แทนตัวเลขฐานสิบหกจำนวน 2 หลัก

การใช้งานตัวแปร (Variables)

ถ้าต้องการใช้งานตัวแปร เพื่ออ้างอิงข้อมูลตามชนิดของข้อมูลใดๆ ในภาษา Lua ก็ทำได้โดยการประกาศและกำหนดค่าเริ่มต้นให้ตัวแปรนั้น ซึ่งจะเป็นข้อมูลชนิดใดก็ได้ แต่ถ้าไม่กำหนดค่าให้หรืออ้างอิงข้อมูลใดๆ ก็ให้กำหนดค่าให้เป็น nil และเป็นการยกเลิกการใช้ตัวแปรนั้นๆ   ประโยคคำสั่งในการกำหนดค่าให้ตัวแปรจะมีชื่อตัวแปรอยู่ด้านซ้ายของโอเปเรเตอร์ = (assignment operator) และทางขวามือเป็นนิพจน์ (expression) ซึ่งให้ค่าได้ การตั้งชื่อตัวแปร ก็เหมือนในภาษา C ยกเว้นคำที่สงวนไว้ (reserved words)

คำสงวนในภาษา Lua (Reserved Words)

คำที่ห้ามนำไปตั้งชื่อ identifier สำหรับชื่อตัวแปรหรือฟังก์ชันในภาษา Lua มีดังต่อไปนี้
   and break do else elseif end false for
   function if in local nil not or repeat 
   return then true until while
และที่ควรรู้อีกประการหนึ่งคือ ภาษา Lua เป็นภาษาที่จำแนกความแตกต่างระหว่างตัวพิมพ์ใหญ่และเล็ก (case-sensitive)
โค้ดตัวอย่าง: ex-1.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 1
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

-- This is a one-line comment.

--[[
   This is a multiple-line comment.
--]]

s1 = 'hello '      -- immutable string (with single quote)
s2 = "world"       -- immutable string (with double quote)
s3 = '!'
s4 = [[
This is Line 1.
This is Line 2.
This is Line 3.
]]

print(s1,s2,s3)           -- output: hello   world   !
io.write(s1,s2,s3,'\n')   -- output: hello world!
print(s1..s2..s3)         -- output: hello world!

io.write(s4)
-- output:
-- This is Line 1.
-- This is Line 2.
-- This is Line 3.

print ('\\,\',\"')            -- output: \,',"

-- show a string with four characters, each specified in hex format (ASCII code)
print ('\x61\x62\x63\x64')    -- output: abcd
--------------------------------------------------------------------------


ชนิดข้อมูลพื้นฐานในภาษา Lua

ตัวแปรสามารถอ้างอิงข้อมูลที่เป็นตัวเลข (number) ค่าลอจิกหรือบูลีน (boolean) และข้อความ (string) ซึ่งเป็นชนิดข้อมูลพื้นฐานในภาษา Lua ข้อมูลแบบตัวเลขมีสองชนิดคือ ค่าที่เป็นเลขจำนวนเต็ม (integer number) และค่าที่เป็นเลขทศนิยม (floating-point number) ถ้าต้องการทราบชนิดข้อมูลของตัวแปรใดๆ ให้ใช้คำสั่ง type() ซึ่งจะให้ค่ากลับคืนเป็นข้อความที่ระบุชนิดของข้อมูลที่ตัวแปรนั้นอ้างอิง เช่น 'number', 'boolean' และ 'string' เป็นต้น
ถ้าต้องการแปลงชนิดข้อมูลของตัวแปร ก็มีคำสั่งอย่างเช่น tonumber() ที่แปลงข้อความให้เป็นตัวเลข และ tostring() และแปลงตัวเลขให้เป็นข้อความ
การใช้ฟังก์ชันทางคณิตศาสตร์ ก็มีไลบรารี่ math ของภาษา Lua ให้ใช้งาน เช่น คำสั่ง math.floor(), math.ceil(), math.sin(), math.cos(), math.exp() และ math.pow() เป็นต้น

โค้ดตัวอย่าง: ex-2.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 2
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

x = 0                       -- define a variable x / assign a number (int) to x
print ('x =', x)            -- output: x =     0
io.write('x = ', x, '\n')   -- output: x = 0

x = nil                     -- undefine a variable x / assign nil to x
print ('x = ', x)           -- output: x =     nil

print ('----------')

f = 1.2345e+2               -- define a variable x / assign a number (double) to x
print (type(f))             -- output: number
io.write ('f = ', f, '\n')

print ('----------')

y = math.floor(f)           -- compute the largest integer less than f
io.write ('y = ', y, '\n')  -- output: y = 123

y = math.ceil(f)            -- compute the smallest integer greater than f
io.write ('y = ', y, '\n')  -- output: y = 124

y = math.sin( math.pi/2 )   -- compute sin(PI/2)
io.write ('y = ', y, '\n')  -- output: y = 1

y = math.cos( math.pi )     -- compute cos(PI)
io.write ('y = ', y, '\n')  -- output: y = -1

y = math.exp( 0 )           -- compute e^0
io.write ('y = ', y, '\n')  -- output: y = 1

y = math.pow( 2, 0.5 )      -- compute the square root of 2
io.write ('y = ', y, '\n')  -- output: y = 1.4142135623731

print ('----------')

z = tonumber("1.5")+1       -- convert a string to a number
print (type(z))             -- output: number
io.write ('z = ', z, '\n')  -- output: z = 2.5

t = tonumber('0x' .. tostring(10))
print ('t = ' .. t)         -- output: t = 16
--------------------------------------------------------------------------


ประโยคที่ทำขั้นตอนตามเงื่อนไขและการทำซ้ำ

การทำกลุ่มคำสั่งที่ขึ้นอยู่กับเงื่อนไข จะอาศัยประโยคแบบ if-else เพื่อตรวจสอบเงื่อนไขจากนิพจน์ที่ให้ค่าเป็น true หรือ false และทำคำสั่งตามแต่ละเงื่อนไขที่กำหนดไว้ และการใช้ประโยคคำสั่งแบบ for-do เพื่อทำคำสั่งซ้ำตามจำนวนครั้งที่ต้องการ (looping) หรือตามเงื่อนไขที่กำหนดและอาจจะไม่ทราบจำนวนครั้งที่ต้องทำ
การเขียนนิพจน์สำหรับใช้เป็นเงื่อนไข จะต้องเป็นนิพจน์ที่ให้ค่าแบบ boolean หรืออาจได้จากการใช้โอเปเรเตอร์เปรียบเทียบค่า (relational operators) อย่างเช่น > (มากกว่า) < (น้อยกว่า) >= (มากกว่าหรือเท่ากับ) <= (น้อยกว่าหรือเท่ากับ) == (เท่ากับ) และ ~= (ไม่เท่ากับ) เพื่อให้ได้ค่าเป็น true หรือ false และยังใช้โอเปเรเตอร์เชิงลอจิก (logical operators) อย่างเช่น and, or และ not กับนิพจน์ที่ให้ค่าทางลอจิกได้อีกด้วย
คำสั่ง io.write() ใช้สำหรับแสดงข้อความออกทางเอาต์พุต แต่ถ้าต้องการจะรับค่าที่เป็นข้อความจากอินพุตของระบบ ให้ใช้คำสั่ง io.read() และเป็นการรับข้อความหนึ่งบรรทัด
ถ้าต้องการสร้างตัวเลขสุ่ม ก็สามารถใช้คำสั่งจากไลบรารี่ math ได้เช่น math.randomseed() เพื่อกำหนดค่าเริ่มต้น (seed) ให้กับตัวสร้างเลขสุ่ม (random generator) และ math.random() เพื่อสร้างเลขสุ่มที่เป็นเลขจำนวนเต็ม

โค้ดตัวอย่าง: ex-3.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 3
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

io.write('Please enter a number: ') 
-- read string from standard input and convert to a number
x = tonumber( io.read() )  
print ('x = '..x)

-- if-elseif-else statement
if x < 0 then
   print ('x is a negative number.')
elseif x > 0 then
   print ('x is a positive number.')
else
   print ('x is zero.')
end 

print ('current time = '..os.time()) -- read system time in seconds

math.randomseed( os.time() ) -- set the seed for the random number generator

x = math.random(-10,10)      -- create a random integer number between [-10,10]
print ('x='..x)
if (x > 0) then
  t = true;
else
  t = false;
end

print ('t = '..tostring(t))

print ('----------')

for i=1,10 do  -- repeat for 10 times
   local x = math.random() -- create a random real number between [0,1)
   print (tostring(i)..') '..x)
end

c = math.random(0,2); -- create a random value [0,2] and assign to c
if (c) then -- Warning: always true
  print('c = '..c);
end
--------------------------------------------------------------------------


ความแตกต่างระหว่างตัวแปรภายนอกและภายใน

การประกาศใช้ตัวแปรแบ่งได้เป็น 2 รูปแบบคือ ตัวแปรภายนอก (global variables) ที่มีขอบเขตการใช้งานครอบคลุมทั้งโปรแกรม และตัวแปรภายใน (local variables) ซึ่งมีขอบเขตและอายุการใช้จำกัดอยู่ตามประเภทของประโยคคำสั่ง หรือโครงสร้างที่ใช้งาน ถ้าไม่ระบุ ตัวแปรเมื่อกำหนดค่าให้จะเป็นตัวแปรภายนอก แต่ถ้าต้องการใช้งานแบบตัวแปรภายใน ให้เขียนกำกับด้วยคำว่า local ตามตัวอย่าง ให้สังเกตผลการทำงานของโค้ด ex-4.lua

โค้ดตัวอย่าง: ex-4.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 4
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

x,y = nil,nil;            -- undefine variables x and y

if (x==nil) then          -- if x is 'equal to' nil.
  x = 1                   -- assign a number to x (global variable)
end

if (x ~= nil) then        -- if x is 'not equal to' nil.
  io.write('x = ',x,'\n') -- show the value of the variable x
else
  io.write('x is nil.','\n')
end
-- output: x = 1
print ('----------')

if (y == nil) then        -- if y is 'equal to' nil.
  local y = 1             -- assign a number to y (local variable)
end

if (y ~= nil) then        -- if y is 'not equal to' nil.
  io.write('y = ',y,'\n') -- show the value of the variable y
else
  io.write('y is nil.','\n')
end
-- output: y is nil.
print ('----------')

-- note: variable 'i' is a local variable within the following for statement.
for i=1,5 do -- for i=1,2,..,5  
  local z=i*i;
  io.write('z = ',tostring(z),'\n'); 
end

if (z ~= nil) then        -- if z is 'not equal to' nil.
  io.write('z = ',z,'\n') -- show the value of the variable z
else
  io.write('z is nil.','\n')
end
-- output: z is nil.

if (i ~= nil) then        -- if i is 'not equal to' nil.
  io.write('i = ',i,'\n') -- show the value of the variable i
else
  io.write('i is nil.','\n')
end
-- output: i is nil.
--------------------------------------------------------------------------


การใช้ประโยคคำสั่งเพื่อทำซ้ำ (Looping)

ประโยคคำสั่งสำหรับการทำซ้ำหรือวนลูป ซึ่งอาจจะมีการซ้อนกันได้มากกว่าชั้น (nested loop) มีอยู่สามรูปแบบในภาษา Lua ได้แก่ ประโยคคำสั่งแบบ for-do, while-do และ repeat-until โดยทั่วไปแล้ว ประโยค for-do จะอาศัยตัวแปรภายในหนึ่งตัวเป็นตัวนับ (count variable) และนำไปกำหนดนิพจน์เงื่อนไขการทำซ้ำ มีทั้งการนับขึ้นและนับลงของตัวนับ และมีการทำซ้ำที่ ทราบจำนวนครั้งแน่นอน อย่างไรก็ตาม การทำซ้ำแบบไม่ทราบจำนวนครั้งล่วงหน้า หรือขึ้นอยู่กับเงื่อนไขในขณะที่โปรแกรมทำงาน ก็สามารถใช้ประโยคทั้งสามแบบได้ได้เช่นกัน นอกจากนั้นประโยคคำสั่ง break จะใช้สำหรับการหยุดการทำงานของลูปได้ทันที

โค้ดตัวอย่าง: ex-5.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 5
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

-- for-do loop
n = 4
for i=0,n do -- for i=0,1,2,...,n
  print( 'i='..i )
end
print ('---------')

-- while-do loop
i=0;
while i < n do -- for i=0,1,2,..,(n-1)
  print( 'i='..i )
  i = i+1
end
print ('---------')

-- repeat-until loop
i = 0
repeat  -- for i=0,1,2,..,(n-1)
  print( 'i='..i )
  i=i+1
until i==n
print ('---------')

-- for loop, count-up
for i=1,n do  -- for i=1,2,...,n
  io.write('i=',i,'\n')
end 
print ('---------')

-- for loop, count-down
for i=n,1,-1 do -- for i=n,n-1,...,2,1
  io.write('i=',i,'\n')
end 

while true do
  io.write('Please enter a number: ')
  local x = io.read()
  if (x == '0') then -- stop the loop if x is '0'
    break
  end
end

--------------------------------------------------------------------------


การสร้างฟังก์ชัน

ฟังก์ชัน (functions) คือกลุ่มของประโยคคำสั่งที่ใช้สำหรับทำงานใดงานหนึ่งภายในโปรแรกม ถ้าต้องการสร้างฟังก์ชันเพื่อใช้งาน ก็ทำได้โดยใช้โครงสร้าง function ซึ่งมีส่วนประกอบคือ function name, function arguments และ function body ตามตัวอย่างในโค้ด ex-6.lua ฟังก์ชันสามารถมีรายการของอาร์กิวเมนต์ (function arguments) หรือไม่มีก็ได้ ภายในอาจมีคำสั่ง return เพื่อหยุดการทำงานต่อไปของฟังก์ชัน ฟังก์ชันสามารถให้ค่ากลับคืนได้ (return value) ไม่มีก็ได้ หรือให้ค่ากลับคืนเป็นข้อมูลได้มากกว่าหนึ่งตัวก็ได้
เมื่อสร้างฟังก์ชันใหม่แล้วสามารถนำไปใช้กับตัวแปรได้ หรือกล่าวได้ว่า ตัวแปรสามารถอ้างอิงฟังก์ชันได้ และฟังก์ชันสามารถเป็นได้ทั้งฟังก์ชันภายนอก (global function) และฟังก์ชันภายใน (local function) ขึ้นอยู่ว่าจะประกาศเป็นแบบใด (มีคำว่า local นำหน้าหรือไม่)
ถ้าต้องการสร้างฟังก์ชันที่มีรายการหรือจำนวนของอาร์กิวเมนต์ ไม่ระบุชัดเจนหรือไม่แน่นอน (function with variable argument) ก็มีวิธีสร้างในภาษา Lua ได้ตามโค้ดตัวอย่าง
ข้อสังเกต: คำสั่ง ipairs() ซึ่งใช้กับอาร์เรย์หรือตารางในภาษา Lua คือ สิ่งที่เรียกว่า "generic for iterator" ทำหน้าที่เข้าถึงข้อมูลในตาราง หรืออาร์เรย์ทีละตำแหน่ง และจะใช้กับประโยค for-in-do ในขณะที่มีการวนลูปนั้นจะได้ครั้งละสองค่า ตัวแรกเป็นเลขลำดับของข้อมูล (เริ่มนับตั้งแต่ 1) และตัวที่สองเป็นข้อมูลตามที่อยู่ดังกล่าวในอาร์เรย์

โค้ดตัวอย่าง: ex-6.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 6
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

f = function (x)      -- define a new function and assign it to a variable
  return (x ^ 2)      -- return the square of x as a floating-point number
end

print (type(f))       -- output: function

for i=1,5 do
  print (f(i))        -- call function 'f'
end

print ('---------')

-- fibonacci, n=0,1,2,...
function fib(n)       -- define a function that computes the Fibonacci number
  if n < 2 then 
    return 1
  end
  return fib( n-2 ) + fib( n-1 ) -- recursive calls
end

for i=0,5 do -- for i=0,1,..,5
  print ( fib(i) )
end
print ('---------')

f = nil -- undefine the variable f

function f(...) -- define a function with dynamic argument list
  local args = {...} -- access the argument list of the function
  for i,v in ipairs(args) do -- for each argument with its integer index
     print (i, v) -- show the index (i) and the argument (v)
  end
end

f('a', 5, true) -- call function 'f'
print ('---------')

function show_numbers(count,start,step)
   local num   = count or 0 -- if count is nil then num is set to 0.
   local value = start or 0 -- if start is nil then value is set to 0.
   local delta = step or 1  -- if step is nil then delta is set to 1.
   for i=1,num do
     io.write( value, ' ')
     value = value + delta;
   end
   io.write('\n')
end

show_numbers()        -- output: 
show_numbers(5)       -- output: 0 1 2 3 4
show_numbers(5,-2)    -- output: -2 -1 0 1 2
show_numbers(5,2,-1)  -- output: 2 1 0 -1 -2
--------------------------------------------------------------------------


การใช้งานโครงสร้างข้อมูลแบบอาร์เรย์

อาร์เรย์ หรือที่เรียกว่า ตาราง (table) ในภาษา Lua เป็นโครงสร้างข้อมูลประเภทหนึ่ง โดยทั่วไปจะใช้งานได้สองแบบคือ เก็บข้อมูลที่เหมือนหรือต่างชนิดกันก็ได้ (และรวมถึงฟังก์ชันด้วย) สามารถเข้าถึงได้โดยใช้หมายเลขที่อยู่ซึ่งเป็นเลขจำนวนเต็มไปตามลำดับที่จัดเก็บ (เหมือนในภาษาอื่นๆ) และใช้โอเปเรเตอร์ [ ] กับตัวแปรแบบอาร์เรย์เพื่อการเข้าถึงข้อมูลข้างใน ถ้าต้องการทราบจำนวนข้อมูลในอาร์เรย์หรือตาราง ก็ใช้โอเปเรเตอร์ # เขียนนำหน้าตัวแปรแบบอาร์เรย์ ส่วนการเพิ่มข้อมูลลงในตารางหรือลบออก ก็สามารถใช้คำสั่ง table.insert() และ table.remove() ได้ตามลำดับ
อาร์เรย์แบบที่สองเป็นการใช้งานแบบ associative array เป็นข้อมูลเป็นคู่ ตัวแรกคือ key ซึ่งเป็น string และตัวที่สองคือ value ที่เป็นข้อมูลชนิดใดก็ได้ และจะกล่าวถึงในตัวอย่างถัดไป

โค้ดตัวอย่าง: ex-7.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 7
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

function sum( a ) -- a function that sums up values in the table
  local sum=0
  if type(a) == "table" then -- if the variable 'a' is a table.
     for i=1,#a do
        sum = sum + a[i] 
     end
     return sum
  else
     return nil
  end
end

t = {1,2,3,4}  -- create a table with four elements and assign it to variable t

print (type(t)) -- output: table
print ('number of elements in the table  : '..#t)
print ('sum of all elements in the table : '..sum(t)) 

for i=1,#t do -- for i=1,2,...,#t
   print( tostring(i) .. ') ' .. t[i] ) -- show each element in the table
end
print ('----------')

print('#t = '..#t) -- number of elements in t

-- append a table to another table
z = {5,6,7}
for i=1,#z do
  t[#t+i]= z[i] -- insert each element from table 'z' to table 't'
end

print('#t = '..#t) -- number of elements in t 

for i,v in pairs(t) do
   print (tostring(i) .. ') ' .. v)    -- show the element
   t[i] = nil  -- undefine / delete element at position i
end

print('#t = '..#t) -- output: #t = 0 
print ('----------')

x = {'a','b'}
y = {'c','d','e'}
t  = {}

for i,e in ipairs(x) do -- for each element in table x 
  t[#t+1] = e           -- append an element to table t (method 1)
end

for i,e in ipairs(y) do -- for each element in  table y 
  table.insert(t, e)    -- append an element to table t (method 2) 
end

for i,e in ipairs(t) do -- show elements in t
  print (i, e)
end
print ('------------')

local compare = function (a,b)
   return a > b
end
-- use the function 'compare' to sort elements in the table
table.sort( t, compare ) 

for i,e in ipairs(t) do -- show elements in t after sorting
  print (i, e)
end
print ('------------')

n = #t
for i=1,n do -- show elements in t after sorting
  table.remove(t,1) -- remove the first element from the table
end
print ('#t = '..#t) -- output: #t = 0
t = nil             -- remove reference to table object
print ('-----------')

-- a table of the names of months
days = {
 [1] = "Sunday", [2] = "Monday", [3] = "Tuesday", [4] = "Wednesday",
 [5] = "Thursday", [6] = "Friday", [7] = "Saturday"
}
for i=1,7 do print( days[i] ) end
print ('-----------')

-- the same as above
days = { "Sunday", "Monday", "Tuesday",
 "Wednesday", "Thursday", "Friday", "Saturday"
}
for _,day in ipairs(days) do print( day ) end

-- create a 3x3 matrix (two-dimensional array)
m = {} 
for i=1,3 do
  m[i] = {}
  for j=1,3 do
     m[i][j] = i*j   -- assign a number to the cell at (i,j)
  end
end
--------------------------------------------------------------------------


การใช้งานโครงสร้างข้อมูลแบบ Associative Arrays

โค้ด ex-8.lua สาธิตการใช้งานอาร์เรย์ที่เก็บข้อมูลเป็นคู่ระหว่างสองสิ่งที่เรียกว่า กุญแจ (key) และข้อมูล (value) ถ้าจะเข้าถึงข้อมูล value ต้องอาศัยข้อความ key สำหรับการค้นหาในตาราง รวมถึงการเพิ่มหรือลบข้อมูลออกจากอาร์เรย์ และการเข้าถึงข้อมูลในอาร์เรย์
ข้อสังเกต: คำสั่งทั้ง ipairs() และ pairs() เป็น generic for iterator ใช้สำหรับการเข้าถึงข้อมูลในตารางหรืออาร์เรย์ทีละตำแหน่ง มีรูปแบบการทำงานแตกต่างกันคือ ipairs() ไม่สามารถใช้ได้กับตารางแบบ associative array

โค้ดตัวอย่าง: ex-8.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 8
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

-- create two dictionaries (associative arrays)
x = {
  ['one'] = 1,
  ['two'] = 2, 
}
y = { ['three'] = 3, ['four'] = 4 }

-- create an empty table
t = {}
for k,v in pairs(x) do
  t[k] = v  -- insert (k,v) from table x into table t
end

for k,v in pairs(y) do
  t[k] = v  -- insert (k,v) from table y into table t
end
-- add more elements into table t
t["five"] = 5
t["six"]  = 6

print ('#t = '..#t)
for k,v in pairs(t) do
  print (k,v)
  t[k] = nil -- remove an element that matches the key
end
print ('#t = '..#t)
print ('-----------')

-- note: Since Lua 5.2, table.foreach is deprecated.
if not table.foreach then
  table.foreach = function(t, f) -- define function table.foreach
    for k, v in pairs(t) do f(k, v) end
  end
end

t = { 
  th='Thailand', 
  de='Deutschland', 
  ['jp']='Japan', 
  ['fr']='France' 
}
-- show all key-value pairs in the table
table.foreach( t, function(k,v) print (k,v) end ) 
--------------------------------------------------------------------------


การใช้งานตัวแปรที่เก็บข้อมูลแบบ String

โค้ด ex-9.lua สาธิตการใช้ตัวแปรแบบสตริง (string) จากตัวอย่างเห็นได้ว่า ตัวแปรแบบสตริงมีฟังก์ชันให้เรียกใช้งานได้ โดยเขียนสัญลักษณ์ : ต่อท้ายชื่อตัวแปรที่เป็นสตริง (เช่น s) แล้วตามด้วยชื่อฟังก์ชัน อย่างเช่น s:len() จะได้ความยาวของสตริง, s:upper() ให้สตริงใหม่ที่ถูกแปลงเป็นตัวพิมพ์ใหญ่, s:lower() ให้สตริงใหม่ที่ถูกแปลงเป็นตัวพิมพ์เล็ก, s:byte() ให้ค่าของไบต์ในตำแหน่งที่ระบุในสตริง, s:sub() ให้สตริงใหม่โดยนำข้อมูลมาจากช่วงตำแหน่งที่ระบุ

โค้ดตัวอย่าง: ex-9.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 9
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

s = "abcd\x21"              -- assign a string of length = 5 to a variable 
print (type(s))             -- output: string
len = #s                    -- get the string length
print ('#s = '..len)        -- output: #s = 5
print ('#s = '..s:len())    -- output: #s = 5

for i=1,len do
  local b = s:byte(i)       -- get the i-th byte in the string
  print ( b )               -- output: 97 98 99 100 33
end
print ('---------')

for i=1,len do
  local p = s:sub(1,i)      -- get a substring, starting from index 0 to i
  print ( p ) 
end
print ('---------')

t = {'a','b','c','d'}
s = table.concat(t, '')    -- convert a table into string
print ('s = '..s)          -- output: s = abcd
print ('---------')

s = table.concat(t, ',')   -- convert a table into string
print ('s = '..s)          -- output: s = a,b,c,d
print ('---------')

u = s:upper()  -- get a copy of string s, but with uppercase chars
print (u)
u = u:lower()  -- get a copy of string u, but with lowercase chars
print (u)
--------------------------------------------------------------------------


การใช้ฟังก์ชันจากไลบรารี่ String ของ Lua

นอกเหนือจากการเรียกใช้ฟังก์ชันผ่านตัวแปรแบบสตริงแล้ว ยังมีอีกวิธีสำหรับการจัดการกับสตริง ซึ่งก็คือการใช้ฟังก์ชันจากไลบรารี่ string ของ Lua เช่น string.len(), string.format(), string.char(), string.byte(), string.upper(), string.lower(), string.rep(), string.find(), string.gsub, string.match() และ string.gmatch() เป็นต้น (ศึกษาเพิ่มเติมได้จาก http://www.lua.org/pil/20.html)
ข้อสังเกต: รูปแบบการเขียนคำสั่ง string.len(s) ให้ผลเหมือน s:len() ถ้าให้ s เป็นตัวแปรที่อ้างอิงข้อความ ดังนั้นแบบหลังนั้นเป็นรูปแบบที่ช่วยเขียนคำสั่งได้สั้นกว่าแบบแรก

โค้ดตัวอย่าง: ex-10.lua
#!/usr/bin/env lua

-- Learning Lua: Code Example 10
-- Author: RSP @ Embedded Systems Lab (ESL), KMUTNB, BKK/Thailand
-- Last Modified: 2015-04-11

s = 'Hello!'
print ( string.format("%s %q",s,s) )        -- output: Hello! "Hello!"
x = 10
print ( string.format("0x%02x %d",x,x) )    -- output: 0x0a 10
y = 123.456 
print ( string.format("%e %.2f",y,y) )      -- output: 1.234560e+002 123.46
print ('---------')

s = string.char(97)                -- create a string from a single number (byte) 
print ('s = '..s)                  -- output: s = a
s = string.char(97,98,99,100)      -- create a string from 4 numbers 
print ('s = '..s)                  -- output: s = abcd
-- get the length of string s
print (#s,string.len(s),s:len())   -- output: 4     4     4

for i=1,#s do
   b = string.byte(s,i)            -- get the value of a ASCII char at index=i in the string
   io.write(b, ' ')                -- show the value
end
io.write('\n')                     -- output: 97 98 99 100
print ('---------')

print ( string.rep('*',10) )       -- output: **********
print( ('*'):rep(10) )             -- output: **********

s = "abcdefghijk"                  -- declare a variable that refers to a string
-- get a substring from s
print (string.sub(s,1,4))          -- output: abcd

-- get a new string from s with uppercase characters
print ( string.upper(s) )          -- output: ABCDEFGHIJK
print ('---------')

s = 'My favorite color is ${color}. I have a pair of ${color} shoes.'
s = string.gsub(s,'${color}','red') -- substitute the substring ${color} with a string
print(s)        -- output: My favorite color is red. I have a pair of red shoes.
print ('---------')

s = 'The temperature is -8.5 Celsius.'
pattern = "[-]?%d+.%d"          -- define a 'regex' pattern that matches a floating-point number
temp = string.match(s, pattern) -- find the first match
print( 'Temp='..temp)           -- output: Temp=-8.5 
print ('---------')

s = 'data: 3,-4,-13,0,193'      -- define a string that contains integer numbers
pattern = "([-]?%d+)"           -- define a 'regex' pattern that matches integers
for number in string.gmatch (s, pattern) do
    print( number )             -- show the next integer
end
--------------------------------------------------------------------------


แหล่งข้อมูลอ้างอิงและศึกษาเพิ่มเติม


เผยแพร่ภายใต้ลิขสิทธิ์ / This work is licensed under: Creative Commons Attribution-NonCommercial 3.0 Unported

ไม่มีความคิดเห็น:

แสดงความคิดเห็น

Set MongoDB in the windows path environment

  Let’s set MongoDB in the windows environment in just a few steps. Step 1: First download a suitable MongoDB version according to your mach...