【问题标题】:Define default values for function arguments定义函数参数的默认值
【发布时间】:2011-08-26 17:20:55
【问题描述】:

在 Lua wiki 中,我找到了一种为缺少的参数定义默认值的方法:

function myfunction(a,b,c)
    b = b or 7
    c = c or 5
    print (a,b,c)
end

这是唯一的方法吗? PHP 样式myfunction (a,b=7,c=5) 似乎不起作用。并不是说Lua方式不起作用,我只是想知道这是否是唯一的方法。

【问题讨论】:

    标签: function lua


    【解决方案1】:

    在我看来,没有其他方法。这就是 Lua 的心态:没有多余的装饰,除了一些语法糖,没有多余的方法来做简单的事情。

    【讨论】:

    • 下面的 Stuart P. Bentley 的回答完全否定了这个答案,其中函数是用表构造函数调用的。这是 Lua 的优势之一:虽然它没有太多多余的装饰,但 Lua 的基本构建块允许您做无限的事情,这对于语言的小尺寸和简单性来说确实非常了不起。
    • @ColinDBennett 感谢您的发言:看起来 OP 阅读了您的评论,并在 12 月相应地更改了接受的答案。 (为了清楚起见,现在是“Stuart P. Bentley's answer above”:wink :)
    【解决方案2】:

    从技术上讲,有 b = b == nil and 7 or b(应该在 false 是有效值的情况下使用 false or 7 计算结果为 7),但这可能不是您想要的。

    【讨论】:

    • 如果您不检查false,更简单的方法是将变量放在最前面,将默认值放在最后。 b = b or 7
    • 既然 OP 在他们的问题中提到了这一点,我认为这是多余的(问题是关于定义默认变量的方法除了 b = b or 7)。
    【解决方案3】:

    如果您想要命名参数和默认值,如 PHP 或 Python,您可以使用表构造函数调用您的函数:

    myfunction{a,b=3,c=2}
    

    (这在 Lua 的很多地方都可以看到,例如 the advanced forms of LuaSocket's protocol modulesIUPLua 中的构造函数。)

    函数本身可以有这样的签名:

    function myfunction(t)
        setmetatable(t,{__index={b=7, c=5}})
        local a, b, c =
          t[1] or t.a, 
          t[2] or t.b,
          t[3] or t.c
        -- function continues down here...
    end
    

    参数表中缺少的任何值都将从其元表中的__index 表中获取(请参阅the documentation on metatables)。

    当然,使用表构造函数和函数可以实现更高级的参数样式——你可以编写任何你需要的东西。例如,here 是一个构造函数的函数,该函数从定义参数名称和默认值的表中获取命名或位置参数表,以及获取常规参数列表的函数。

    作为非语言级别的功能,可以更改此类调用以提供新的行为和语义:

    • 可以使变量接受多个名称
    • 位置变量和关键字变量可以穿插 - 定义两者可以优先考虑其中任何一个(或导致错误)
    • 可以制作仅关键字的无位置变量,也可以制作无名称的仅位置变量
    • 可以通过解析字符串来完成相当详细的表构造
    • 如果函数是用 1 个表以外的东西调用的,则可以逐字使用参数列表

    编写参数转换器的一些有用函数是 unpack(在 5.2 中移至 table.unpack)、setfenv(在 5.2 中已弃用,新的​​ _ENV 构造)和 select(返回单个值来自给定的参数列表,或列表长度为'#')。

    【讨论】:

    • A 我刚开始使用 lua,我会暂时保持简单,但您的帖子信息量很大。以后可能会派上用场。谢谢。
    • 在大多数情况下,保持简单是要走的路。元参数接口仅对具有大量可选属性的对象(如 UI 对象)才是真正需要的。
    • 我认为这个答案是解决问题的人,而不是当前标记为接受的人。感谢您的启发:)
    • 应该注意,这个回复中也使用的x or default 表达式并不是真正等同于参数默认值,而只是一个简单的解决方法,只有在nilfalse 都为无效的参数值。假设布尔参数x 的默认值是true,调用者传递一个显式false。然后x or true 给出true,即使false 已显式传递。更好的版本是if x == nil then x = default end,它也更具可读性;它仍然无法处理明确的nil 参数。
    • 哦,嘿,这是现在公认的答案!好的。 (作为记录,为了将@Undo 的评论放在上下文中,jpjacobs 下面的答案是很长一段时间以来公认的答案:我几乎得到了a second Populist badge。)
    【解决方案4】:

    到目前为止,我发现的唯一有意义的方法是做这样的事情:

    function new(params)
      params = params or {}
      options = {
        name = "Object name"
      }
    
      for k,v in pairs(params) do options[k] = v end
    
      some_var = options.name
    end
    
    new({ name = "test" })
    new()
    

    【讨论】:

      【解决方案5】:

      如果您的函数不希望将布尔值 falsenil 作为参数值传递,那么您建议的方法很好:

      function test1(param)
        local default = 10
        param = param or default
        return param
      end
      
      --[[
      test1(): [10]
      test1(nil): [10]
      test1(true): [true]
      test1(false): [10]
      ]]
      

      如果您的函数允许将布尔值false 而非nil 作为参数值传递,您可以按照Stuart P. Bentley 的建议检查是否存在nil,只要默认值即可不是布尔值false:

      function test2(param)
        local default = 10
        param = (param == nil and default) or param
        return param
      end
      
      --[[
      test2(): [10]
      test2(nil): [10]
      test2(true): [true]
      test2(false): [false]
      ]]
      

      当默认值为 Boolean false 时,上述方法会中断:

      function test3(param)
        local default = false
        param = (param == nil and default) or param
        return param
      end
      
      --[[
      test3(): [nil]
      test3(nil): [nil]
      test3(true): [true]
      test3(false): [false]
      ]]
      

      有趣的是,颠倒条件检查的顺序确实允许布尔 false 成为默认值,并且名义上性能更高:

      function test4(param)
        local default = false
        param = param or (param == nil and default)
        return param
      end
      
      --[[
      test4(): [false]
      test4(nil): [false]
      test4(true): [true]
      test4(false): [false]
      ]]
      

      这种方法的工作原理似乎违反直觉,直到进一步检查,发现它们有点聪明。

      如果您希望允许允许传递nil 值的函数的默认参数,则需要做一些更丑陋的事情,例如使用可变参数:

      function test5(...)
        local argN = select('#', ...)
        local default = false
        local param = default
        if argN > 0 then
          local args = {...}
          param = args[1]
        end
        return param
      end
      
      --[[
      test5(): [false]
      test5(nil): [nil]
      test5(true): [true]
      test5(false): [false]
      ]]
      

      当然,可变参数完全阻止使用它们的函数中的函数参数的自动完成和 linting。

      【讨论】:

        【解决方案6】:

        简短的回答是这是最简单和最好的方法。在 lua 中,变量默认等于 nil 。这意味着如果我们不将参数传递给 lua 函数,则参数是 exits 但为 nil 并且 lua 程序员使用此 lua 属性来设置默认值。

        这也不是设置默认值的方法,但您可以使用以下功能

        这个函数创建一个错误是你没有将值传递给参数

        function myFn(arg1 , arg2)
        err = arg1 and arg2
        if not err then error("argument") end
        -- or
        if not arg1 and arg2 then error("msg") end
        

        但这不是一个好方法,最好不要使用这个功能

        在图表中显示 [,arg] 中的可选参数

        function args(a1 [,a2])
        -- some
        end
        function args ( a1 [,a2[,a3]])
        -- some
        end
        

        【讨论】:

          猜你喜欢
          • 2018-07-08
          • 1970-01-01
          • 2021-04-08
          • 2011-02-20
          • 2011-04-09
          • 2014-03-28
          • 2010-11-28
          • 1970-01-01
          • 2019-09-11
          相关资源
          最近更新 更多