Tải bản đầy đủ (.docx) (26 trang)

Học lua trong 30 phút

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (326.89 KB, 26 trang )

Học Lua trong 30 phút
1 tháng 7, 2018



lua
learning

Lua là gì?
Ngơn ngữ lập trình kịch bản bậc cao với các đặc điểm: kiểu động, nhẹ, nhanh, đa hình, đa tính
năng và mã nguồn mở.

Nhẹ chỗ nào?


Lua được viết bằng C với hơn hai chục nghìn dịng code!



Trình thơng dịch Lua chỉ có kích thước vài trăm KB.



Bộ nhớ mà Lua sử dụng khi chạy cũng rất ít.

Nhanh hơn Python khơng?


Bộ xử lý Lua bao gồm trình biên dịch, dịch code thành bytecode và máy ảo để thực thi
code đó




Kiến trúc máy ảo của Lua từ v5.x trở đi sử dụng mô hình thanh ghi theo kiến
trúc x86 (trước đó là sử dụng mơ hình ngăn xếp)



Tất nhiên là nhanh hơn Python nhiều (có thể nói là nhanh nhất trong các họ ngơn ngữ kịch
bản phổ biến). Lua có một phiên bản tên là LuaJIT, thay vì dịch ra bytecode thì nó dịch ra mã
máy.
Khơng so sánh với CPython, PyPy... mà có gán mác JIT vào cũng thua LuaJIT, chấp V8 luôn.


Ngôn ngữ kịch bản luôn gắn liền với từ thông dịch, ở đây Lua cho code vào và chạy luôn.
Xuất hiện thêm từ biên dịch là do Lua dịch code sang bytecode rước khi cho vào máy ảo.

Đa hình ra sao?


Lua hỗ trợ lập trình hàm và cả hướng đối tượng.



OOP chủ yếu thông qua prototype, tựa tựa JS vậy.

Làm được gì mà đa tính năng?





Lua có thể dùng để viết ứng dụng, game, web (backend) và cả hệ thống.
Lua xuất hiện nhiều trong cả lập trình nhúng, đi kèm với các ngôn ngữ nhanh như C/C+
+, Rust để dễ dàng triển khai, tái sử dụng các API.
Có thể tham khảo các project về Lua tại đây, ở đây và cả đây nữa.
Nhúng ở đây khơng phải là lập trình mạch mà là Lua hỗ trợ CAPI để nhúng vào các ngôn ngữ
khác.
Một số game engine hay tools hack game hỗ trợ script Lua cũng là một hình thức nhúng.

Cài đặt Lua
Lua không kén thằng C compiler nào cả, hỗ trợ trên nhiều kiến trúc khác nhau nữa. Phiên bản
release mới nhất là 5.3.5, nhưng ổn định nhất và được sử dụng nhiều vẫn là 5.1.5.
$ curl -o lua.tar.gz
$ tar -xvf lua.tar.gz
$ cd lua-5.1.5
$ make && make install

Chọn editor
Muốn đa nền tảng thì cứ quất Sublime Text, có một số package hỗ trợ autocomplete và cả just-intime syntax checker. VS Code cũng ngon (có nhiều extension hỗ trợ Lua và cả debug).
Ngồi ra cịn có một IDE được viết hồn tồn bằng Lua (sử dụng wxWidget UI) vơ cùng nhanh và
nhẹ, đó là ZeroBrane Studio, nó hỗ trợ chủ yếu là code Lua và các game engine có Lua built-in, có
live-coding khá ngon.
Trên Windows, ta có thể sử dụng Lua Studio, trọn gói cài đặt chỉ bằng giao diện.
Lua có một package manager tên là LuaRocks, tựa tựa như vcpkg, conan... hỗ trợ cài đặt các thư
viện ngoài nhanh chóng.


Hello Lua
$ echo print("Hello, world!") > test.lua

Hoặc tạo một file và gõ code sau vào:

print("Hello, world!")

Trên một số code editor/IDE chỉ cần nhấn Ctrl + B hoặc chạy lệnh sau:
$ lua ./test.lua

1. Chú pháp và biến
Note: Các hướng dẫn được viết trong code block, bạn có thể copy chúng và chạy. Hãy cẩn thận vì
có tiếng Việt, khơng nên set file test với encoding là UTF8 with BOM.
-- Hai dấu trừ đánh dấu comment trên một dòng.
--[[
Thêm hai cặp ngoặc vng vào
để comment
trên nhiều dịng.
--]]

local a
-- local là từ khóa.
-- Khai báo biến a, nếu khơng gán gì thì nó là nil.
-- nil có thể hiểu là chưa định nghĩa, không mang giá trị nào.

a=4
-- Gán giá trị cho biến.


-- Số trong Lua đều là số thực double,
-- nhưng biến a vẫn được hiểu là số nguyên.

A = 4.0
-- Số thực.
-- Trong Lua phân biệt giữa chữ in hoa và chữ thường.

-- Khơng dùng local thì A sẽ là biến toàn cục.

print(a, b)
-- print để in giá trị ra console.
-- Biến b chưa được khai báo sẽ là nil, khơng lỗi đâu
-- vì nó được hiểu là biến global.

a=5b=6
-- Viết trên một dòng, cách nhau bằng khoảng trắng.
-- Lua không cần chấm phẩy, nhưng phải đúng biểu thức.

b = 11; print(b)
-- Có chấm phẩy.

local x, y, z = 1, 2, 3, 4
-- Khai báo & gán giá trị lần lượt cho nhiều biến.
-- Tất nhiên 4 sẽ thừa.


-- Khai báo một chuỗi.
s = 'dấu nháy đơn'
n = "dấu nháy kép cũng được"
u = [[
chuỗi trên
nhiều dòng bằng
hai hai cặp ngoặc vuông]]

-- Nối hai chuỗi bằng hai dấu chấm ..
x = 'abc'..'def'
print(x..'789')


p = print -- Tuy print là một hàm, nhưng cũng là kiểu dữ liệu.
print = 20 -- Tất cả các biến đều thay đổi giá trị được.
p(print)

-- In ra 20.

print = p -- Trả lại như cũ.

2. Rẻ nhánh và câu điều kiện
b = true -- Kiểu đúng/sai boolean.

if b then
print('yes')


else
print('no')
end
-- In ra yes.
-- Kết thúc một statement luôn là end.

x = 123
if x == 456 then
print('false')
elseif x ~= 789 then

-- Dấu khác.

print('true')

else
print('otherwise')
end
-- In ra true

-- Trong Lua, 0 và false khác nhau.
-- Nếu cho vào if, 0 vẫn đúng,
-- còn false và nil đều sai.

-- Logic or, and.
print(false and nil)
print(0 and nil)

-- > false
-- > nil


print(true and nil)

-- > nil

print(false and 0)

-- > false

print(true and false) -- > false
print(1 and 0)

-- > 1


-- if trên một dòng.
print(1 > 6 and 4 or 3)
-- > In ra 3
print(0 and 'true' or 'false')
-- > In ra true, vì 0 là đúng mà.

3. Vịng lặp
for i = 1, 10 do -- Từ 1 đến <= 10, i sẽ tăng 1.
print(i)
end

for i = 20, 10, -1 do -- i giảm 1.
print(i)
end

n=0
while (n < 5) do
n=n+1


end
-- Do -- dùng cho comment nên sẽ khơng có ++.

repeat
n=n+1
until n > 5
-- Có thằng này là khơng kết thúc bằng end.

4. Hàm
-- Khai báo hàm.

function foo()
print('Hello World!')
end

-- Gọi hàm.
foo() -- In ra Hello World!

-- Khai báo kiểu lambda.
fib = function(n)
if n < 2 then
return 1
end
return fib(n - 2) + fib(n - 1)


end

-- Hàm trả về nhiều kết quả.
function mulret(a, b, c)
print(a, b, c)
return 4, 5, 6, 7, 8
end

x, y, z = mulret(5)
-- > 5 nil nil ; tham số b, c sẽ là nil.

-- Hàm trả về chỉ gán 4, 5, 6 vào x, y, z; 7 và 8 thừa.
print(x, y, z) -- Kiểm tra, chỉ in ra 4 5 6.

-- Thêm local vào trước thì là hàm cục bộ.

local function g(x) print(x) end
local g; g = function (x) print(x) end
-- Hai thằng như nhau.

g((((((1))))))
g 'qwerty'

-- In ra qwerty.

-- Trường hợp gọi hàm khơng cần cặp ngoặc trịn khi
-- tham số được cách tên hàm bằng các kí tự cú pháp


-- như: ngoặc nhọn { (table), dấu nháy " hoặc ' (chuỗi).

-- Lua còn hỗ trợ cả ...
function vargs(...)
print(...)
end

vargs(11, 'a', 4+5) -- > In ra 11 a 9.

5. Bảng (table)
-- Đây là kiểu cấu trúc phức hợp của Lua,
-- tương tự như array trong PHP hay object trong JS.

t = {key1 = 'value1', key2 = false}

-- Sử dụng dấu chấm để tham chiếu đến phần tử con.
print(t.key1) -- In ra value1

t.newKey = {} -- Thêm newKey, giá trị là một table.
t.key2 = nil

-- Xóa key2

-- Sử dụng giá trị để đánh dấu phần tử con.
u = {['@!#'] = 'qbert', [{}] = 1729, [6.0 + 0.28] = 'concho'}
-- Sử dụng cặp ngoặc [ ] và cho biểu thức vào trong.


print(u[6.28]) -- In ra concho.

a = u['@!#']
b = u[{}]

-- a = 'qbert'
-- b = nil, khơng phải 1729 nhé.

-- Vì key này là table rỗng,
-- cần phải sử dụng hai table giống nhau.

-- Sử dụng table cho tham số của hàm.
function h(x) print(x.key1) end
h {key1 = 'AK-47'} -- In ra AK-47.

-- Mảng (list / arrays):
v = {'value1', 'value2', 1.21, 'gigawatts'}
for i = 1, #v do -- #v để lấy độ dài, dùng được cho cả chuỗi.
print(v[i]) -- Array trong Lua "start at 1" nhé! =))
end


local a = {11, 22, 55, 77}
local b = {x = 10, y = 15, pi = 3.14}

-- foreach index.
for i,v in ipairs(a) do
print(i,v)


end
-- foreach với key.
for k,v in pairs(b) do
print(k,v)
end

6 Metatable, metamethod (prototype)
-- Một table có thể có metatable,
-- nó sẽ nhận nạp chồng một table khác.

f1 = {x = 1, y = 2}
f2 = {x = 5, y = 6}

-- Sẽ sinh lỗi nếu:
-- s = f1 + f2
-- Vì khơng thể cộng hai table.

-- Tạo metatable.
my_meta = {}
function my_meta.__add(a, b)
local ret = {}

ret.x = a.x + b.y
ret.y = a.x - b.y


return ret
end

-- Set protptype cho cả hai.
setmetatable(f1, my_meta)
setmetatable(f2, my_meta)

r1 = f1 + f2 -- Gọi .__add(f1, f2) trong metatable của f1.
r2 = f2 + f1 -- Tương tự luôn, metatable của f2.
print(r1.x, r1.y) -- > 7 -5
print(r2.x, r2.y) -- > 7 3

-- Hiểu đơn giản hơn thì một table bình thường,
-- chỉ để chứa dữ liệu mà thôi,
-- metatable thêm vào sẽ là bộ tiền xử lý cho nó.

-- Thêm table vào table thông qua key __index.
defaultFavs = {animal = 'dog', food = 'donuts'}
myFavs = {food = 'pizza'}
setmetatable(myFavs, {__index = defaultFavs})
eatenBy = myFavs.animal

-- > 'dog'

-- Giá trị của __index, __add, .. được gọi là metamethod.



-- Full list, a là một table với một metamethod.
--[[
__add(a, b)

cho a + b

__sub(a, b)

cho a - b

__mul(a, b)

cho a * b

__div(a, b)

cho a / b

__mod(a, b)

cho a % b

__pow(a, b)

cho a ^ b

__unm(a)

cho -a


__concat(a, b)
__len(a)
__eq(a, b)

cho a .. b
cho #a
cho a == b

__lt(a, b)

cho a < b

__le(a, b)

cho a <= b

__index(a, b)

<hàm hoặc một table> cho a.b

__newindex(a, b, c)
__call(a, ...)

cho a.b = c

cho a(...)

--]]


7 Lớp và kế thừa
-- class khơng được tích hợp sẵn (khơng như C++, Java...)
-- Có nhiều cách khác nhau để tạo thông qua
-- việc sử dụng table và metatable.


Dog = {}

-- 1.

function Dog:new()

-- 2.

newObj = {sound = 'woof'}
self.__index = self

-- 3.
-- 4.

return setmetatable(newObj, self) -- 5.
end

function Dog:makeSound()

-- 6.

print('I say ' .. self.sound)
end


mrDog = Dog:new()

-- 7.

mrDog:makeSound() -- > 'I say woof'

-- 8.

-- 1. Dog giống như một class, nhưng thực chất là table.

-- 2. Hàm tablename:func(...) được hiểu như
-- hàm tablename.func(self, ...)
-- dấu hai chấm : thêm self vào
-- thành tham số thứ nhất.
-- Đọc 7 & 8 bên dưới để hiểu nó thêm như nào.


-- 3. newObj sẽ là instance mới cho class Dog.

-- 4. self = class mới tạo ra. Thông thường
-- self = Dog, nhưng phần kế thừa sẽ thay đổi nó.
-- newObj get các hàm từ chính nó nhưng set
-- metatable của newObj và __index của nó
-- vào chính nó (Dog).

-- 5. Nên nhớ: setmetatable sẽ return tham số đầu.

-- 6. Dấu hai chấm : như trong mục 2, nhưng self này
-- có thể sử dụng cho lớp con kế thừa thông qua Dog.new().


-- 7. Giống như Dog.new(Dog), self = Dog trong new().
-- 8. Giống như mrDog.makeSound(mrDog); self = mrDog.

----------------- Ví dụ kế thừa.
----------------

LoudDog = Dog:new()

function LoudDog:makeSound()

-- 1.


s = self.sound .. ' '

-- 2.

print(s .. s)
end

seymour = LoudDog:new()

-- 3.

seymour:makeSound() -- > 'woof woof'

-- 4.

-- 1. LoudDog lấy method & property từ Dog.


-- 2. Bản thân nó có key 'sound' từ hàm new().

-- 3. Giống như LoudDog.new(LoudDog),
-- và được chuyển thành Dog.new(LoudDog),
-- LoudDog khơng có key 'new', nhưng nó có
-- __index = Dog trong metatable của nó (LoudDog).
-- Kết quả: metatable của seymour là LoudDog, và
-- LoudDog.__index = LoudDog. Nên seymour.key sẽ
-- = seymour.key, LoudDog.key, Dog.key, bất kỳ
-- table nào cũng là cái đầu tiên với key nhận được.

-- 4. Key 'makeSound' có sẵn trong LoudDog, seymour kế thừa,
-- nó giống như LoudDog.makeSound(seymour).


-- Nếu cần tạo thêm class con mới, cấu trúc sẽ như sau:

function LoudDog:new()
newObj = {} -- tạo newObj
self.__index = self
return setmetatable(newObj, self)
end

8. Tạo module
Module giống như một thư viện riêng, và người dùng có thể sử dụng nó thơng qua:
local mod = require('module_name')

Có 2 loại module bao gồm:




Lua module: viết bằng Lua, được xem như một hàm.
C module: thường được viết bằng C hoặc bất kỳ ngôn ngữ nào, được biên dịch dưới dạng
thư viện liên kết động.
Đầu tiên, tạo một file mới làm module:
-- Khởi tạo table M.
-- Đây là biến cục bộ, chỉ sử dụng được trong file này.
local M = {}

Thêm mộ số giá trị vào table M:
local M = {}

M.a = 1
M.b = true
M.c = 'Hello'


M.foo = function(self)
print(self.c)
end

Và trả về M ngay cuối file:
print(self.c)
end

return M

Tiếp tục tạo một file mới để chạy code:
local mod = require('module')
-- Load module ở trên, lưu ý tên file.

-- Nếu file module.lua nằm trong thư mục con thì
-- require('folder.module')
-- có thể thay '.' thành '/' hoặc '\\'

print(mod.a)

-- > 1

print(mod.b)

-- > true

mod:foo()

-- > 'Hello'

-- Hoặc mod.foo(mod).

Nên nhớ, biến local trong main.lua sẽ không dùng được trong module.lua. Nếu quy về hàm hoặc
sử dụng cho cùng một file thì sẽ như này:
local function module()


local M = {}
-- ...
return M
end

mod = module()


Ngồi ra có thể chạy file Lua khác ngay trong chương trình.
dofile('abc.lua')
-- Chạy abc.lua,
-- tất nhiên là không lưu các biến từ file đó,
-- khơng giống như require đâu.

local f = loadfile('abc.lua')
-- loadfile sẽ load một file nhưng không chạy ngay mà lưu vào hàm.
-- Sử dụng f() để chạy file.

Các module chuẩn
Lua cung cấp một số module chuẩn dành cho các nhu cầu cơ bản, tất nhiên là không cần
dùng require đâu, trừ khi biến của thư viện được bạn gán cho một giá trị nào đó.


io



math



os



string




table

io.write("Hello\n") -- Tương tự print().



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×