lua 函式 預設值 乙個易用的Lua命令列解析器

2021-10-13 16:00:08 字數 4709 閱讀 6528

過去幾年一直在使用lua開發手機遊戲,同時也使用python開發一些輔助工具。這些工具一般是一些命令列程式,因此就涉及到命令列引數的解析工作。在使用python做命令列解析時,有乙個極其好用的庫click(command line inte***ce creation kit的縮寫),它提供了command/option/argument/group等decorator,使用它們修飾你的入口函式,即可輕鬆實現命令列解析以及usage/help資訊的生成。例如下面是乙個簡單使用click的示例程式:

import click

@click.command()

@click.option("-s", "--speaker", help = "specify the name of speaker.")

@click.argument("name")

def hello(name, **options):

'''say hi to somebody.'''

click.echo('hello %s!' % name)

if options["speaker"]:

click.echo("%40s" % ("-- from " + options["speaker"]))

if __name__ == "__main__":

hello()

把上述**儲存為hello.py,然後在命令列中輸入python hello.py world,會得到如下輸出:

hello, world!

在進行進一步說明之前,我們需要先約定一些術語名稱,以免發生誤解。

一般來說,乙個簡單的命令格式如下:

proc options arguments

其中proc程式名/命令名options命令選項arguments命令引數。例如命令gcc -o a.out sample.c main.c,其中gcc為命令名,-o a.out部分為選項,sample.c main.c則為引數。

還有一種更複雜的情況,即包含子命令的命令(稱之為命令組)。例如git commit -m "comment" file1 file2 file3,其中git就是乙個命令組,commitgit命令組中的乙個子命令。包含子命令的命令格式如下:

proc options subcommand options arguments

其中第乙個options修飾proc,第二個options修飾subcommandarguments屬於子命令,由子命令負責讀取和處理。

上述格式可以通過把簡單命令格式中的arguments替換成subcommand options arguments得到。甚至可以繼續替換,形成多層巢狀的子命令:

proc options subcommand options [sub-subcommand options]* arguments

前面我們執行示例程式時,輸入了python hello.py world命令,它可以認為是命令組python包含了子命令hello.py,也可以直接把python hello.py理解為乙個命令。後面這種理解顯然更加符合邏輯,如果你使用python的setup機制,甚至可以為hello.py這個指令碼提供乙個更簡潔的命令名稱而無需再使用python命令。

回到前面的示例程式。它可以接受命令選項-s。輸入python hello.py -s hailong world(其中的-s也可以替換成完整形式--speaker),則輸會輸出:

hello, world!

-- from hailong

$ python hello.py

usage: hello.py [options] name

error: missing argument "name".

$ python hello.py -x

error: no such option: -x

使用--help選項,還會顯示幫助資訊:

$ python hello.py --help

usage: hello.py [options] name

say hi to somebody.

options:

-s, --speaker text specify the name of speaker.

--help show this message and exit.

示例程式雖短,但作為命令列程式,對於命令列的處理已經相當完善。

我們在開發遊戲的過程中,往往需要實現一些gm命令,用於修改玩家資料以方便開發與測試。有一種辦法:專門開發乙個ui介面,為每個gm命令新增一些按鈕(以及可能需要的輸入框),以此響應gm命令。當新增一條gm命令時,需要編輯ui並響應ui,過程並不是很方便。另外還有一種辦法:使用乙個控制台介面(接收文字輸入以及顯示文字輸出,可以在遊戲中製作乙個專用介面,也可以在電腦上啟動乙個命令列程式利用區域網連線到手機),在程式中解析輸入的gm命令並執行。在這種方式下,如果能提供方便的命令列解析,實現gm命令就會變得十分方便,而且使用的時候也會顯得逼格滿滿!

由於是使用lua開發遊戲的,因此需要乙個lua版本的命令列解析庫。在luarocks上簡單搜尋後,並未找到很好用的第三方庫。所以就自己手動擼了乙個庫lua-click並分享了出來(參見lua-click on github或lua-click on luarocks)。它只有乙個原始檔click.lua,既可以在桌面平台(windows或mac osx等)的lua環境下執行,也可以被包含到遊戲中去使用。

在桌面平台下,可以這樣使用(這段**與上述的python示例**功能一致):

local function main(cmd, options, arguments)

print(string.format("hello, %s!", arguments["name"]))

if options["speaker"]~=nil then

print(string.format("%40s", "-- from " .. options["speaker"]))

endendlocal cli = require("click")

local maincommand = cli.functioncommand ,

},arguments = ,

},entry_func = main,

}if cli.__name__()=="__main__" then

cli.main(maincommand, nil, arg)

end

上述示例**中使用了click模組中的functioncommand類,用它可以基於乙個入口函式建立乙個command例項,使用main函式執行即可它(另外的兩個引數分別是命名的顯示名稱和引數陣列)。__name__函式類似於python的__name__變數,可用來確定當前指令碼是被直接執行的,還是被其它模組require的。functioncommand的入口函式接受3個引數:cmd為建立的command例項本身(它本身有一些方法可供使用,例如printf()函式可用於輸出文字,help()函式可用於輸出幫助資訊);options引數是乙個包含了所有命令選項的table(示例**中它包含speaker字段,其值為使用者輸入的-s--speaker選項的值);arguments是乙個包含了所有命令引數的table(示例中它包含name字段)。

下面將具體介紹lua-click中常用的類和函式。更多詳細的引數可見**中的文件注釋。

commandgroup有乙個方法函式addcommand(name, command),可用於為該命令組新增子命令。

executefilecommand基於乙個入口檔案定義乙個命令。它是basecommand的子類。構造引數除了basecommand所支援的字段,還額外支援:

lua 函式 預設值 定義函式引數的預設值

如果你想要命名引數和預設值,如php或python,你可以使用表構造函式呼叫你的函式 myfunction 函式本身可以有這樣的簽名 function myfunction t setmetatable t,local a,c t 1 or t.a,t 2 or t.b,t 3 or t.c fun...

函式引數的預設值與解構賦值的預設值

function foo 物件,沒有預設值,只有解構賦值引數的預設值 console.log x,y foo undefined 5 foo 1 5 foo 1 2 foo typeerror cannot read property x of undefined上面 只使用了物件的解構賦值預設值,...

方法引數 預設值 ES6 函式的預設值

es6 之前,不能直接為函式的引數指定預設值,只能採用變通的方法。function log x,y log hello hello world log hello 你好 hello china 這裡可以看到,檢查函式log的引數y有沒有賦值,如果沒有,則指定預設值為 哈嘍 這種寫法的缺點在於,如果引...