2019年12月13日金曜日

table:filter(-'')について

GearSwapのtriggers.luaの43行目には以下のコードがある。

windower.register_event('outgoing text',
                                         function(original,modified,blocked,ffxi,extra_stuff,extra2)
    windower.debug('outgoing text')
    if gearswap_disabled then return modified end
   
    local splitline = windower.from_shift_jis(windower.convert_auto_trans(modified))
                              :gsub(' <wait %d+>',''):gsub('"(.-)"',
            function(str) return str:gsub(' ',string.char(7))
            end):split(' '):filter(-'')

最後の文「filter(-'')」は謎めいている。

なお、括弧の中の記号はマイナス、シングルクォーテーションx2である。
そして、関数filterはaddons\libs\functions.luaの406行目で定義されている関数で、引数で与えられた値に該当する要素だけを抜き出したテーブルを返す関数となっている。その名の通り一般的にフィルタ処理と呼ばれるものに該当する。

上記のコードはマイナス記号がなければsplitが返したテーブルから空文字だけを抜き出す処理になるが、コードの意図をくみ取れば本来はその逆であり、マイナス記号は「空文字はいらないよ」という宣言になっていると思われる。

このマイナス記号は結論から言うとaddons\libs\strings.luaの19行目にて定義されている。
debug.setmetatable('', {
    __index = function(str, k)
                    return string[k] or type(k) == 'number' and string.sub(str, k, k) or (_raw and _raw.error or error)('"%s" is not defined for strings':format(tostring(k)), 2)
                    end,
    __unm = functions.negate .. functions.equals,
    __unp = functions.equals,
})

上記のとおり文字列クラスに単項マイナス(__unm)をオーバーロードしている。__unmは「等しいかどうか(equals)」を実行した後、さらにその結果を「反転する(negate)」を実行する関数として定義されている。つまり、文字列に単項マイナス記号を付けると、文字列から一転して関数になってしまうのだ。

関数filterは引数として関数も受け取れるようにできている。すなわち、-''を引数として渡すと空文字の要素を排除して空文字ではない要素だけを抜き出したテーブルが返ってくる。

なお、関数の連結(..)は functions.lua の 236行目で __concat を定義して演算子をオーバーロードすることで実装している。
debug.setmetatable(functions.empty, {
    __index = index,
    __add = add,
    __sub = sub,
    __concat = functions.pipe,
    __unm = functions.negate,
    __class = 'Function'
})

0 件のコメント:

コメントを投稿