9.函数

9.函数


9.1 知识点

函数的基本语法

命名函数语法

  • 声明:
function 函数名()
    -- 函数体
end
  • 调用:
函数名()

匿名函数语法

  • 声明:
装载函数的变量 = function()
    -- 函数体
end
  • 调用:
装载函数的变量()

函数是一等公民:可存变量、传参、返回。闭包、Upvalue 可以后面再了解。

无参数无返回值的函数

命名的无参数无返回值的函数

-- 命名的无参数无返回值的函数
-- F1() -- 不能在未声明函数前调用函数,否则会报错
function F1()
    print("我是命名的无参数无返回值的函数F1")
end

F1() -- 我是命名的无参数无返回值的函数F1

匿名的无参数无返回值的函数

-- 匿名的无参数无返回值的函数
F2 = function()
    print("我是匿名的无参数无返回值的函数F2")
end

-- 用 F2 装载了函数,有点类似 C# 中用一个变量保存委托
F2() -- 我是匿名的无参数无返回值的函数F2

有参数的函数

  • 参数写在括号里,不用声明类型。
function F3(a)
    print("我是有参数的函数F3")
    print(a)
    -- print("参数是" .. tostring(a)) -- 用 .. 拼接时,nil / boolean 最好先 tostring
end

-- 有参数的函数在括号中传入参数进行调用
F3(1)     -- 1
F3("123") -- 123
F3(true)  -- true

-- 如果传入的参数和函数参数个数不匹配
-- 不会报错,只会补 nil 或者丢弃多余参数
F3()        -- nil
F3(nil)     -- nil
F3(1, 2, 3) -- 1,后面的 2 和 3 被丢弃

和 C# 不同:参数个数不匹配不会报错,少传回补 nil,多传会丢弃。业务里要自己判断参数是否允许为空。

有返回值的函数

单返回值的函数

-- 单返回值的函数
-- 在函数体使用 return 返回变量
function F4(a)
    print("我是单返回值的函数F4")
    return a
end

-- 用一个变量接返回值
temp = F4(1)
print(temp) -- 1

多返回值的函数

-- 多返回值的函数
-- 在函数体使用 return 返回多个变量,变量间用逗号隔开
function F5(a)
    print("我是多返回值的函数F5")
    return a, "123", true
end

-- 用多个变量来接多个返回值,按位置一一对应
-- 如果变量不够,多出来的返回值会被丢弃
-- 如果变量多了,多出来的变量会被赋值 nil
temp1, temp2, temp3, temp4 = F5("1")
print(temp1) -- 1
print(temp2) -- 123
print(temp3) -- true
print(temp4) -- nil

函数的类型

  • 装载函数的变量类型是 function
F6 = function()
    print("我是被查看函数类型的函数F6")
end

-- 使用 type 方法查看装载函数的变量类型
print(type(F6)) -- function

函数的重载

  • Lua 不支持重载;同名后者覆盖前者。
-- 无参函数
function F7()
    print("我是无参函数F7")
end

-- 有参函数,已经把上面的无参函数顶掉了
function F7(str)
    print("我是有参函数F7")
    print(str)
end

-- 尝试不传参数调用无参函数
-- 但无参函数已经被有参函数顶掉,所以调用的是后面的有参函数
F7() -- 我是有参函数F7 nil

变长参数

  • 括号里写 ... 接收变长参数。
function F8(...)
    -- 变长参数使用一个表存起来
    local arg = { ... }

    -- #arg 可以得到变长参数表的长度
    print("我是变长参数F8,参数的长度是" .. #arg .. ",传进来的参数如下")

    -- 再对表进行遍历输出
    for i = 1, #arg do
        print(arg[i])
    end
end

F8(1, "123", true, 4, 5, 6) -- 1 "123" true 4 5 6

local arg = { ... },避免变长参数表污染全局。

函数嵌套

  • 函数返回值也可以是函数。

函数返回命名函数

-- 函数返回命名函数
function F9()
    local F99 = function()
        print("我是F9函数内嵌套并返回出去的函数F99")
    end

    return F99
end

f9 = F9() -- F9() 调用后会返回一个函数,用 f9 作为装载函数的变量去接
f9()      -- 我是F9函数内嵌套并返回出去的函数F99

函数返回匿名函数

-- 函数返回匿名函数
function F10()
    return function()
        print("我是F10函数内嵌套并返回出去的匿名函数")
    end
end

f10 = F10() -- F10() 调用后会返回一个函数,用 f10 作为装载函数的变量去接
f10()       -- 我是F10函数内嵌套并返回出去的匿名函数

函数可作返回值,有点像C#返回委托的感觉。


9.2 知识点代码

Lesson9_函数.lua

print("**********函数************")

print("**********知识点一 函数的基本语法************")

-- 命名函数语法:
-- 声明:
-- function 函数名()
--     函数体
-- end
-- 调用:
-- 函数名()

-- 匿名函数语法:
-- 声明:
-- 装载函数的变量 = function()
--     函数体
-- end
-- 调用:
-- 装载函数的变量()

print("**********知识点二 无参数无返回值的函数************")

-- 命名的无参数无返回值的函数
-- F1() -- 不能在未声明函数前调用函数,否则会报错
function F1()
    print("我是命名的无参数无返回值的函数F1")
end

F1() -- 我是命名的无参数无返回值的函数F1

-- 匿名的无参数无返回值的函数
F2 = function()
    print("我是匿名的无参数无返回值的函数F2")
end

-- 用 F2 装载了函数,有点类似 C# 中用一个变量保存委托
F2() -- 我是匿名的无参数无返回值的函数F2

print("**********知识点三 有参数的函数************")

-- 有参数的函数在函数括号中写入参数,不需要声明参数类型
function F3(a)
    print("我是有参数的函数F3")
    print(a)
    -- print("参数是" .. tostring(a)) -- 用 .. 拼接时,nil / boolean 最好先 tostring
end

-- 有参数的函数在括号中传入参数进行调用
F3(1)     -- 1
F3("123") -- 123
F3(true)  -- true

-- 如果传入的参数和函数参数个数不匹配
-- 不会报错,只会补 nil 或者丢弃多余参数
F3()        -- nil
F3(nil)     -- nil
F3(1, 2, 3) -- 1,后面的 2 和 3 被丢弃

print("**********知识点四 有返回值的函数************")

-- 单返回值的函数
-- 在函数体使用 return 返回变量
function F4(a)
    print("我是单返回值的函数F4")
    return a
end

-- 用一个变量接返回值
temp = F4(1)
print(temp) -- 1

-- 多返回值的函数
-- 在函数体使用 return 返回多个变量,变量间用逗号隔开
function F5(a)
    print("我是多返回值的函数F5")
    return a, "123", true
end

-- 用多个变量来接多个返回值,按位置一一对应
-- 如果变量不够,多出来的返回值会被丢弃
-- 如果变量多了,多出来的变量会被赋值 nil
temp1, temp2, temp3, temp4 = F5("1")
print(temp1) -- 1
print(temp2) -- 123
print(temp3) -- true
print(temp4) -- nil

print("**********知识点五 函数的类型************")

-- 装载函数的变量类型是 function
F6 = function()
    print("我是被查看函数类型的函数F6")
end

-- 使用 type 方法查看装载函数的变量类型
print(type(F6)) -- function

print("**********知识点六 函数的重载************")

-- Lua 中的函数不支持重载
-- 同名函数会被最后一个声明的同名函数顶掉
-- 调用时默认调用最后声明的那个函数

-- 无参函数
function F7()
    print("我是无参函数F7")
end

-- 有参函数,已经把上面的无参函数顶掉了
function F7(str)
    print("我是有参函数F7")
    print(str)
end

-- 尝试不传参数调用无参函数
-- 但无参函数已经被有参函数顶掉,所以调用的是后面的有参函数
F7() -- 我是有参函数F7 nil

print("**********知识点七 变长参数************")

-- 在函数括号中写入 ...
function F8(...)
    -- 变长参数使用一个表存起来
    local arg = { ... }

    -- #arg 可以得到变长参数表的长度
    print("我是变长参数F8,参数的长度是" .. #arg .. ",传进来的参数如下")

    -- 再对表进行遍历输出
    for i = 1, #arg do
        print(arg[i])
    end
end

F8(1, "123", true, 4, 5, 6) -- 1 "123" true 4 5 6

print("**********知识点八 函数嵌套************")

-- 函数的返回值也可以是函数类型的变量

-- 函数返回命名函数
function F9()
    local F99 = function()
        print("我是F9函数内嵌套并返回出去的函数F99")
    end

    return F99
end

f9 = F9() -- F9() 调用后会返回一个函数,用 f9 作为装载函数的变量去接
f9()      -- 我是F9函数内嵌套并返回出去的函数F99

-- 函数返回匿名函数
function F10()
    return function()
        print("我是F10函数内嵌套并返回出去的匿名函数")
    end
end

f10 = F10() -- F10() 调用后会返回一个函数,用 f10 作为装载函数的变量去接
f10()       -- 我是F10函数内嵌套并返回出去的匿名函数

-- 函数返回函数这个写法很常见
-- 这里先只理解“函数可以被当成值返回”即可
-- 闭包、Upvalue、外部变量捕获这些机制


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏