又LAG隨性筆記
  • 關於我
  • 作品集
  • 生活隨筆
  • 與我聯絡
  • 隨手扎

隨手扎

October 12, 2020

【30天Lua重拾筆記28】進階議題: Meta Programming

Meta Programming / 元程式設計

元程式設計(英語:Metaprogramming),又譯超程式設計,是指某類電腦程式的編寫,這類電腦程式編寫或者操縱其它程式(或者自身)作為它們的資料,或者在執行時完成部分本應在編譯時完成的工作。多數情況下,與手工編寫全部代碼相比,程式設計師可以獲得更高的工作效率,或者給與程式更大的靈活度去處理新的情形而無需重新編譯。 – 維基百科

簡單說,元程式設計,就是讓「程式能夠編寫程式」,改變程式運行的部份行為。Lua本身具有部份如此的能力,舉例來說,如果想要建立一組變數A-Z,或許正常會這樣子寫:

A = 1
B = 2
C = 3
-- ....
Z = 26

但Lua可以有更聰明(hacking)的寫法:

for i=65, 65+25 do  -- ASCII Code of A is 65
  print(string.char(i))
  _ENV[string.char(i)] = i - 64 -- 1 to 26
end

還記得_ENV的作用嗎?

October 11, 2020

【30天Lua重拾筆記27】進階議題: debug

Lua本身並沒有獨立的debugger相關工具,但他有一個強大的內置套件— debug。

打印調錯訊息traceback

debug = require "debug"

do
  local ten = 0
  function div10(n)
    print(debug.traceback()) -- 打印調錯訊息
    return n / ten
  end
end

更新變數值

透過直接觀看函式內容,可以知道這個函式div10並不符合預期。

do
  local ten = 0
  function div10(n)
    return n / ten
  end
end

所以需要改變ten值,但這次不直接修改程式原始碼。我們得先了解怎麼取得閉包變數ten:

October 10, 2020

【30天Lua重拾筆記26】進階議題: 錯誤處理

作為一個寄宿型的嵌入式語言,Lua設計更傾向由宿主語言(通常是C)處理錯誤。
但是可以在保護模式下,執行函式,並檢查函式是否執行成功。
很像是Go語言。這就是Lua的錯誤處理基本方法。

錯誤處理

作為一個寄宿型的嵌入式語言,Lua設計更傾向由宿主語言(通常是C)處理錯誤。

num = 10
str = "string"

print('Hello, Lua')

result = num / str -- Error: attempt to div a 'number' with a 'string'

print('here will not show, because error hapend before')

一般來說,並不傾向於Lua處理最後,因為數字與字串相除,所引發的錯誤。這個錯誤會持續引發至宿主語言,由宿主語言進行錯誤處裡。

October 9, 2020

【30天Lua重拾筆記25】進階議題: 模組化

Lua並沒有完整的模組系統,更多的是依賴模組開發者的設計。在Lua 5.1曾經有module()的函數可用,但於Lua 5.2已經被移除。更多的需要使用_G、_ENV來使用,相關說明可以參考全局表與環境表。

module (name [, ...])

在require()之前,需要先說一下如何載入程式檔案並執行。

載入檔案

對於模組化設計,最重要的一點是如何切割程式為不同檔案,接著就是如何串連不同檔案。在之前介紹過load,Lua提供了另一個類似的方法loadfile。

示例

首先先建立個 hello.lua 檔案,簡單就好:

print "Hello, World"

然後才是主程式 loadfile_hello_example.lua :

hello = loadfile("./hello.lua")
hello() --> Output: Hello, World

如果你分別於REPL環境打入這兩行指令,你會發現第一行指令並沒有任何輸出結果,只得到一個hello函數。只有在第二行執行函式時,才真正執行hello.lua程式檔案的內容。

執行檔案

October 8, 2020

【30天Lua重拾筆記24】中級議題: coroutine

coroutine

Lua提供coroutine的函式庫,使其有能力編寫不同模式的程式。

thread create

你可以透過coroutine.create()建立一個thread。

t1 = coroutine.create(function() print("Hello, World") end)
print(type(t1)) -- Output: thread

Lua並不是多執行緒的,其thread是輕量的。儘管Lua本身沒有異步(async)的寫法,但可以創造出異步的寫法。相對而言,值執行順序是明確許多的。

thread running

可以透過coroutine.resume()去觸發一個thread的執行:

coroutine.resume(t1) -- Output: Hello, World

傳入參數

可以對一個剛建立好的thread傳入參數。

function hello(name)
  while true do
    coroutine.yield("Hello, " .. name)
  end
end


t1 = coroutine.create(hello)
print(coroutine.status(t1)) -- suspended
print(coroutine.resume(t1, "Bob")) -- Output: Hello, Bob
print(coroutine.status(t1)) -- suspended
print(coroutine.resume(t1, "World")) -- Output: Hello, Bob

thread close

October 7, 2020

【30天Lua重拾筆記23】中級議題: 閉包

變數的查找

對於一個變數,Lua會先嘗試從當前詞法環境(Lexical)尋找,再從當前環境中尋找(_ENV)。
那的對於區塊變數呢??

function parentFunction()
  local L1 = 100
  local function childFunction()
    print("here is child")
  end
  return childFunction
end

f1 = parentFunction(100)
f1()  -- Output: here is child

上例中,區塊變數L1沒有任何人可以存取的到,簡直消失在了時空夾縫之中。

詞法環境(Lexical)

詞法環境(Lexical)指的是程式編寫當下,執行區塊由內而外,可以見到的範圍。

隱藏區塊變數

在Lua變數預設值為nil。透過查找規則,可以暫時隱藏一切區塊變數。

  • ««
  • «
  • 1
  • 2
  • 3
  • 4
  •  … 
  • 21
  • »
  • »»
© 又LAG隨性筆記 2021