【问题标题】:Why optional parameters must appear at the end of the declaration为什么可选参数必须出现在声明的末尾
【发布时间】:2010-05-24 10:03:15
【问题描述】:

在我见过的所有支持可选参数的编程语言中,都有一个模仿,即可选参数必须出现在声明的末尾。可选项目后不得包含必填参数。 这是什么原因?我想这可能是编译器/解释器的要求。

【问题讨论】:

    标签: c# java language-agnostic language-design optional-parameters


    【解决方案1】:

    好吧,如果它们在最前面,您将如何检测它们何时停止供应?唯一的方法是变量类型在可选参数之后 不同。有点奇怪的要求,所以你只需要强制它们放在最后是有道理的(省去​​检测“final”可选参数的复杂规则的麻烦)。

    此外,这是调用函数时最自然的方式。

    【讨论】:

    • 是的,现在看起来很明显:)。谢谢。
    • @Incognito:它在 Ruby 中运行良好。如果可选参数之后有强制参数,则强制参数从参数列表的末尾获取。剩下的都是可选参数。有关示例,请参见 StackOverflow.Com/questions/2896106/…
    【解决方案2】:

    这只是那些特定语言的设计者制定的任意规则。绝对没有技术上的理由应该存在这种限制。

    它在 Ruby 中运行良好:

    def foo(m1, m2, o1='o1', o2='o2', *rest, m3, m4)
      return m1, m2, o1, o2, rest, m3, m4
    end
    
    foo(1, 2, 3, 4)
    # => [1, 2, 'o1', 'o2', [], 3, 4]
    
    foo(1, 2, 3, 4, 5)
    # => [1, 2, 3, 'o2', [], 4, 5]
    
    foo(1, 2, 3, 4, 5, 6)
    # => [1, 2, 3, 4, [], 5, 6]
    
    foo(1, 2, 3, 4, 5, 6, 7)
    # => [1, 2, 3, 4, [5], 6, 7]
    
    foo(1, 2, 3, 4, 5, 6, 7, 8)
    # => [1, 2, 3, 4, [5, 6], 7, 8]
    

    必须提供所有强制参数:

    foo(1, 2, 3)
    # => ArgumentError: wrong number of arguments (3 for 4)
    

    没有其余参数,提供超过 number_of_mandatory + number_of_optional 参数是错误的:

    def bar(m1, m2, o1='o1', o2='o2',  m3, m4)
      return m1, m2, o1, o2, m3, m4
    end
    
    bar(1, 2, 3, 4, 5, 6, 7)
    # => ArgumentError: wrong number of arguments (7 for 6)
    

    参数列表开头的强制参数从参数列表的开头从左到右绑定。参数列表末尾的强制参数从参数列表的末尾从右到左绑定。可选参数从剩余参数列表的开头从左到右绑定。剩下的所有参数都绑定到其余参数。

    【讨论】:

    • 显然是正确的——因为你有一个工作示例要展示。但我会争辩说,类 c 语言大多是由简单的规则构建的,而 ruby​​ 方式是冗长的:这在 c 中会是一个大惊喜,在 c++ 中至少是一个小惊喜。
    • @dmckee:我所知道的唯一具有可选参数的类 C 语言是 C#,但由于可选参数和基于 arity 的重载之间的复杂交互,它的规则非常复杂。我发现它们至少同样复杂,也许 C# 更复杂一点。
    • 这里还有一条更基本的规则:所有可选参数必须是连续的。没错,它们中的一个连续块很容易出现在列表中的任何位置,尽管对基于类型的重载解析(如果有的话)的影响可能非常奇怪。
    【解决方案3】:

    考虑如下声明:

    int foo(float a, int b=0, int c=0, float d);
    

    (注意我是如何在列表中间定义默认参数的)随后被称为类似

    foo(0.0,1,2.0)
    

    电话是什么?特别是 bc 被省略了吗?

    编译器设计者可以通过使用命名参数来解决这个问题

    foo(a=0,c=0,d=2.0)
    

    例如 python 中可用的功能。

    【讨论】:

    • 该功能在 C# 中也可用:foo(a: 0, c: 0, d: 2.0)。问题是在进行位置调用时该怎么做。
    • 这在 Ruby 中运行良好。参数列表开头的强制参数从参数列表的开头从左到右绑定。参数列表末尾的强制参数从参数列表的末尾从右到左绑定。可选参数从剩余参数列表的开头从左到右绑定。剩下的所有参数都必须是其余参数。在没有剩余参数时不提供强制参数或提供超过num_mandatory + num_optional 参数是错误的。
    • 在您的具体示例中,a 将绑定到 0.0d2.0b1c 将获得其默认值 @ 987654334@.
    • @Jore 在上面的例子中,如果我想将 1 传递给 c 并让 b 使用它的默认值,我该怎么办?看起来在 Ruby 中'b' 只是部分可选的......
    【解决方案4】:

    末尾的可选参数允许您在某些时候停止指定参数,例如

    void Test(int a, optional int b = 0, optional int c = 0) { ... } 
    
    Test(3);
    

    如果您将c 设为必需参数,则必须使用如下语法:

    Test(3, , 2);
    Test(a := 3, c := 2);
    

    可选参数的优点是它可以被视为它不存在。如果可选参数位于参数列表的中间,则如果不使用“计数逗号”或使用过于冗长的语法,这是不可能的。

    【讨论】:

    • 这在 Ruby 中运行良好。参数列表开头的强制参数从参数列表的开头从左到右绑定。参数列表末尾的强制参数从参数列表的末尾从右到左绑定。可选参数从剩余参数列表的开头从左到右绑定。剩下的所有参数都必须是其余参数。在没有剩余参数时不提供强制参数或提供超过num_mandatory + num_optional 参数是错误的。
    【解决方案5】:

    随便猜测一下:它可能与调用约定有关(例如,参数从左到右压入堆栈,可选参数被简单地省略以防它们未指定)。

    【讨论】:

    • 我对此表示怀疑,我认为调用者只会推送默认值。
    【解决方案6】:

    Java 和 C# 没有命名参数,所以你不能这样做:

    myfunction(param1='Meh', optionalParam=2)
    

    你必须这样做:

    myfunction('Meh', 2)
    

    否则

    myFunction(2, 'Meh')
    

    模棱两可。编译器应该如何知道您的意思是 2 在可选参数集中?

    【讨论】:

    • C# 4.0 有命名参数。
    猜你喜欢
    • 1970-01-01
    • 2023-04-07
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 2022-10-24
    • 2012-07-16
    相关资源
    最近更新 更多