本文同步發表於個人網站
這是一個強大的工具,要寫的漂亮並不容易,許多語言禁止了他。
Lua保有他。他很靈活,但你也應該慎重考慮是否真的應該使用。
而我認為,開發人員應該要是自由的,這才有創造的價值,這才能體現思考的藝術。就如同松本行弘說的:「語言體現思考的價值」
如果你的想法最初就是這樣想的,就先寫下來吧!「童子軍原則」別忘了逐漸改得更健壯。
Lua保有C/C++裡,goto
的能力,可以跳轉到函數區塊內任意可見的標籤(Label)。標籤的形式由兩個冒號夾成:
:: <Label Name> ::
BTW, Python 認為如果你需要使用到這個功能,表示你應該在拆分程式碼。
有了這強大的能力可以做啥?可以學像ES6那樣跳出外部迴圈:
九九乘法表只計算到6x4
(()=>{
outer:
for(let j = 2; j <= 9; j++){
let line_output = ""
for(let i = 1; i <= 9; i++){
line_output += `${j}x${i}=${j*i},\t`
if(i > 3 && j > 5){
console.log(line_output)
break outer
}
}
console.log(line_output)
}
})()
Lua類似的作法會是:
for j = 2, 9, 1 do
for i = 1, 9, 1 do
io.write(string.format("%2dx%2d=%2d, \t", j, i, j*i))
if i > 3 and j > 5 then
goto finish
end
end
print() -- new line
end
::finish::
print() -- new line
2x 1= 2, 2x 2= 4, 2x 3= 6, 2x 4= 8, 2x 5=10, 2x 6=12, 2x 7=14, 2x 8=16, 2x 9=18,
3x 1= 3, 3x 2= 6, 3x 3= 9, 3x 4=12, 3x 5=15, 3x 6=18, 3x 7=21, 3x 8=24, 3x 9=27,
4x 1= 4, 4x 2= 8, 4x 3=12, 4x 4=16, 4x 5=20, 4x 6=24, 4x 7=28, 4x 8=32, 4x 9=36,
5x 1= 5, 5x 2=10, 5x 3=15, 5x 4=20, 5x 5=25, 5x 6=30, 5x 7=35, 5x 8=40, 5x 9=45,
6x 1= 6, 6x 2=12, 6x 3=18, 6x 4=24,
標籤屬於函式的一部分,只能跳轉到同一個函式內定義的標籤,就算是內部函式跳到外部也不行。所以你不能這樣寫:
function outer()
local function inner()
print("inner")
goto outer_label -- 無法成功跳轉,會報錯
end
inner()
print("outer")
::outer_label::
end
我很驚訝於Common Lisp的狀態系統。有了label
/goto
可以來實現一部分這樣的能力。
不過這不是很符合結構化程式,所以看看就好。
function div(a,b)
::start::
a = tonumber(a)
b = tonumber(b)
if a and b then
if b == 0 then
print("b must be a number, but not 0.")
goto restart_case
end
return a/b
else
goto restart_case
end
::restart_case::
local restart_case = {"Break"}
if a then
table.insert(restart_case, "Use Value")
table.insert(restart_case, "Return Value")
end
print("Please Select Restart Case[1-" .. #restart_case .. "]:")
for i, restart in ipairs(restart_case) do
print(i, restart)
end
select = restart_case[tonumber(io.read())]
print("Select ", select)
if select == "Break" then
goto finish
elseif select == "Use Value" then
goto use_value
elseif select == "Return Value" then
goto return_value
else
goto restart_case
end
::return_value::
do
io.write("Return Value: ")
return tonumber(io.read())
end
::use_value::
io.write("Use Value: ")
b = tonumber(io.read())
goto start
::finish::
end
很可惜的這樣做直接進入的debugger,沒辦法給更上層的程式handle。感覺還需要用全局變數/動態變數,否則可能就真的只剩下setjum
/longjmp
的選項了。
不管怎麼說,沒有Lisp那種程式編輯程式的能力,寫起來真丑?。所以Lisp到底怎麼做到的?