【问题标题】:How should Scala default arguments to refer to a previous positional argument?Scala 的默认参数应该如何引用先前的位置参数?
【发布时间】:2012-10-31 19:40:28
【问题描述】:

Scala-lang 参考 5.5.1 和 6.6.1 给我的印象是默认参数可以引用以前评估过的参数:

class Test(val first: String, val second: String = first)

但从实验看来,这样做的唯一方法是使用以下形式:

class Test(val first: String)(val second: String = first)

然后定义一个辅助构造函数或一个创建伴生类,以避免在创建时指定第二组括号。我不太明白第二个构造函数是如何工作的,它看起来像一个柯里化函数,所以我可能猜想有必要独立于second 评估first,这是正确的吗?这种形式是必要的还是有一些语法糖我可以用来调整第一个构造函数来做我想做的事?

【问题讨论】:

  • current Scala Language Specification 中没有(子)第 5.5.1 节。您的意思是 5.1.1(“构造函数调用”)吗?
  • 是的,应该是 5.1.1。正如@Travis Brown 所指出的,第 5.3 节在评估参数时定义参数的范围将解释编译错误。

标签: scala constructor operator-precedence default-parameters default-arguments


【解决方案1】:

正如Travis Brown 指出的那样,您确实只能在默认表达式中引用来自前一个参数列表的前一个参数(因此您确实需要currify)。

现在,关于您的特定用例,默认参数和方法重载有时是实现同一目标的两种方式。

我认为您的方案最简单的解决方案是简单地定义Test,如下所示:

class Test(val first : String, val second : String) {
  def this(f : String) = this(f, f)
}

如果你想让它更复杂,另一种方法,使用伴随对象:

class Test(val first : String)(val second : String = first)
object Test {
  def apply(f : String) = new Test(f)
  def apply(f : String, s : String) = new Test(f)(s)
}

(一个小的区别是现在你创建的对象没有new。)

不能做的,就是把它定义为:

class Test(val first : String)(val second : String = first) {
  def this(f : String, s : String) = this(f)(s)
}

...因为 curried 版本被翻译成(除其他外)与重载构造函数具有相同签名的方法。

【讨论】:

    【解决方案2】:

    the spec 的 5.3 开始:

    形式值参数的范围包括所有后续 参数部分和模板t

    顺便说一下(从 4.6 开始),常规方法是相同的:

    形式值参数名称的范围x包括所有 后续参数子句,以及方法返回类型和 函数体(如果已给出)。

    即,无论您有构造函数还是普通方法,值参数名称都不在其自己的参数子句的范围内。在您的第二个版本中,构造函数有两个参数子句,first 仅在第二个范围内。有关多参数子句的更多详细信息,请参见 5.3。

    【讨论】:

    • 谢谢,这正是我想要的。
    猜你喜欢
    • 2017-10-16
    • 2017-10-23
    • 2015-03-06
    • 2017-11-13
    • 1970-01-01
    • 2013-10-13
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多