当前位置: 首页 > 工具软件 > Lua Fun > 使用案例 >

Lua注解及代码技巧

赵宏达
2023-12-01

Lua注解

@class类声明注解

EmmyLua利用 @class 注解来模拟面向对象中的类,可以继承,可以定义字段/属性

  • 完整格式:
--@class MY_TYPE[:PARENT_TYPE] [@comment]
  • 应用目标:

    • local 变量
    • global 变量
  • 示例:

    ---@class Car : Transport @define class Car extends Transport
    local cls = class()
    
    function cls:test()
    end
    
  • 示例说明:

    cls 变量标记为 Car 类,在其它地方可以使用 @type 注解来标记目标变量类型,以增强代码提示以及其它功能

@type类型标记注解

利用 @type 注解来标记目标变量的类型,以增强代码提示以及其它功能

  • 完整格式:
---@type MY_TYPE[|OTHER_TYPE] [@comment]
  • 应用目标:

    • local 变量
    ---@type Car|Ship @transport tools, car or ship. Since lua is dynamic-typed, a variable may be of different types
    ---use | to list all possible types
    local transport = {}
    
    • global 变量
    ---@type Car @global variable type
    global_car = {}
    
    • property 属性
    local obj = {}
    ---@type Car @property type
    obj.car = getCar()
    

数组类型

可以利用 MY_TYPE[] 的方式来标注一个数据类型为数组

  • 完整格式:
---@type MY_TYPE[]
  • 示例:
---@type Car[]
local list = {}

local car = list[1]
-- car. and you'll see completion

for i, car in ipairs(list) do
    -- car. and you'll see completion
end

字典类型

可以利用 table<KEY_TYPE, VALUE_TYPE> 的方式来标注一个数据类型为字典

  • 完整格式:
---@type table<KEY_TYPE, VALUE_TYPE>
  • 示例:
---@type table<string, Car>
local dict = {}

local car = dict['key']
-- car. and you'll see completion

for key, car in pairs(dict) do
    -- car. and you'll see completion
end

函数类型

可以利用 fun(param:MY_TYPE):RETURN_TYPE 的方式来标注一个数据类型为函数

  • 完整格式:
---@type fun(param:MY_TYPE):RETURN_TYPE
  • 示例:
---@type fun(key:string):Car
local carCreatorFn1

local car = carCreatorFn1('key')
-- car. and you see code completion

---@type fun():Car[]
local carCreatorFn2

for i, car in ipairs(carCreatorFn2()) do
    -- car. and you see completion
end

@alias 别名注解

可以使用 @alias 将一些复杂不容易输入的类型注册为一个新的别名

  • 完整格式:
---@alias NEW_NAME TYPE
  • 示例
---@alias Handler fun(type: string, data: any):void

---@param handler Handler
function addHandler(handler)
end

@param参数类型标记注解

利用 @param 注解来标记函数定义参数的类型,以增强代码提示以及其它功能

  • 完整格式:
---@param param_name MY_TYPE[|other_type] [@comment]
  • 应用目标:

    • 函数参数
    ---@param car Car
    local function setCar(car)
        ...
    end
    
    ---@param car Car
    setCallback(function(car)
        ...
    end)
    
    • for循环参数
    ---@param car Car
    for k, car in ipairs(list) do
    endc
    
    ---@param instID number
    ---@param str string
    ---@param active boolean
    ---@param obj UnityObject
    ---@param point Vector3
    ---@param pName string|boolean
    ---@param onAnimFinishFn fun():void
    ---@param fn fun(GameObject):void
    ---@param fn fun(x:number, y:number):void
    

@return 函数返回值注解

利用 @return 注解来标记函数的返回值类型

  • 完整格式:
---@return MY_TYPE[|OTHER_TYPE] [@comment]
  • 应用目标:

    • 函数
    ---@return Car|Ship
    local function create()
        ...
    end
    
    ---Here car_or_ship doesn't need @type annotation, EmmyLua has already inferred the type via "create" function
    local car_or_ship = create()
    
    ---@return Car
    function factory:create()
        ...
    end
    
--- 返回多参数
---@return number, number, number @costType, costId, priceTotal

@field 属性注解

利用 @field 注解来标记某个类的额外的属性(即使这个属性没有出现在代码里)

  • 完整格式:
---@field [public|protected|private] field_name FIELD_TYPE[|OTHER_TYPE] [@comment]
  • 应用目标:

    • @class 注解之后
    ---@class Car
    ---@field public name string @add name field to class Car, you'll see it in code completion
    local cls = class()
    

@generic 泛型注解

利用 @generic 注解来模拟高级语言中的 泛型

  • 完整格式:
--@generic T1 [: PARENT_TYPE] [, T2 [: PARENT_TYPE]]
  • 应用目标:

    • function
  • 示例:

    ---@generic T : Transport, K
    ---@param param1 T
    ---@param param2 K
    ---@return T
    local function test(param1, param2)
    -- todo
    end
    
    ---@type Car
    local car = ...
    
    local value = test(car)
    

@vararg 不定参数注解

使用 @vararg 注解一个函数的不定参数部分的类型

  • 完整格式:
---@vararg TYPE
  • 示例

    ---@vararg string
    ---@return string
    local function format(...)
     local tbl = { ... } -- inferred as string[]
    end
    

@language内嵌语言

可以利用 @language 的方式来标注一段文本为某种代码格式,从而可以显示高亮

  • 完整格式:
  ---@language LANGUAGE_ID
  • 示例:
---@language JSON
local jsonText = [[{
    "name":"Emmy"
}]]

@see 引用

可以利用 see 的注解来标注一个引用, 解决隐式调用无法查找到相关引用的问题

---@class Emmy
local emmy = {}
function emmy:sayHello()
	
end

---@see Emmy#sayHello
local function testHello()
	
end

代码技巧

默认值

-- number
a = a or 0
-- string
a = a or "" 
-- function
a = a or function()end
-- table
a = a or {}
-- boolean
a = a == nil and true

多条件分支优化

-- if 优化
local Type_= {
    None = 0,
    A = 1,
    B = 2
}

local Handler = {
   [Type_.None] = function(self, arg, arg2) end,
   
   [Type_.A] = function(self, arg, arg2) 
     
   end,
   
   [Type_.B] = function(self, arg, arg2)
   end,
   }

-- 使用
local arg = 1
local arg2= 2
local type = Type_.A
EffectHandler[type](self, arg, arg2)

3R原则(the rules of 3R)是:减量化(reducing),再利用(reusing)和再循环(recycling)

polyline = {
    { x = 1.1, y = 2.9 },
    { x = 1.1, y = 3.7 },
    { x = 4.6, y = 5.2 },
    ...
}
polyline = {
    x = {1.1, 1.1, 4.6, ...},
    y = {2.9, 3.7, 5.2, ...}
}

Reusing

如果无法避免创建新对象,我们需要考虑重用旧对象。

local t = {}
local aux = {year = nil, month = 6, day = 14}
for i = 1970, 2000 do
  aux.year = i
  t[i] = os.time(aux)
end

枚举

RankType = {
	SSS = "红",
	SS = "橙",
	S = "紫",
	A = "蓝",
	B = "绿",
	C = "白",
}

RankTypes = {
	[1] = {RankType.C, RankType.B, RankType.A},
	[2] = {RankType.S, RankType.SS, RankType.SSS},
}
reward = RankTypes[rewardType]

位运算

浮点数判定

将两个数相减,如果差的绝对值小于一个足够小的数就认为他们相等

减法抽象

两个数字的比较逻辑,可以转换成数字相减,然后用结果当条件去做接下来的处理。

以剪刀石头布为例:

-- Rock Paper Scissor
RPSString = {
	[1] = "剪刀",
	[2] = "石头",
	[3] = "布",
}

RPSRes = {
	Draw = 'D',
	Lose = 'L',
	Win = 'W',
}

-- 对方数值 - 我方数值 对应的结果映射
RPSResMap = {
	[-2] = RPSRes.Lose,
	[-1] = RPSRes.Win,
	[0] = RPSRes.Draw,
	[1] = RPSRes.Lose,
	[2] = RPSRes.Win,
}

RPSTalk = {
	[RPSRes.Draw] = "棋逢对手",
	[RPSRes.Lose] = "棋差一招",
	[RPSRes.Win] = "棋盛一招",
}

local random = math.random
local hisChoice = random(1, 3)
local myChoice = random(1, 3)
local res = RPSResMap[hisChoice - myChoice]
local resString = RPSTalk[res]

参考资料

EmmyLua文档

更简洁的 lua 逻辑代码

 类似资料: