以下代码给我一个Scala 2.11.7错误,这让我感到困惑:
class A(val a: String, val bVal: Option[String] = None) {
val b: String = bVal.getOrElse("")
def copy(a: String = a, b: Option[String] = Some(b)) = new A(a, b)
}
IntelliJ IDE没有显示任何错误,但在编译时出现错误:
Error:(4, 52) type mismatch;
found : Option[String]
required: String
def copy(a: String = a, b: Option[String] = Some(b)) = new A(a, b)
^
为了比较,这编译得很好:
class A(val a: String, val bVal: Option[String] = None) {
val b = bVal
def copy(a: String = a, b: Option[String] = Some(b.getOrElse(""))) = new A(a, b)
}
当我用Some(b)
替换Some(this.b)
时,错误就会消失,但我仍然会混淆为什么错误存在于首位。看起来编译器正在解析b
中的Some
作为copy
的参数,而不是b
的{{1}}成员。如果是这种情况,第二个版本如何编译而没有错误?
答案 0 :(得分:1)
这必须是一个错误。默认表达式的范围包括先前的参数列表。
scala> def x = 1
x: Int
scala> def f(x: Int = x) = 2 * x
f: (x: Int)Int
scala> f()
res0: Int = 2
和-Xprint:typer
显示默认值是正确的:
class A extends scala.AnyRef {
<paramaccessor> private[this] val a: String = _;
<stable> <accessor> <paramaccessor> def a: String = A.this.a;
<paramaccessor> private[this] val bVal: Option[String] = _;
<stable> <accessor> <paramaccessor> def bVal: Option[String] = A.this.bVal;
def <init>(a: String, bVal: Option[String] = scala.None): A = {
A.super.<init>();
()
};
private[this] val b: String = A.this.bVal.getOrElse[String]("");
<stable> <accessor> def b: String = A.this.b;
def copy(a: String = a, b: Option[String] = scala.Some.apply[A](<b: error>)): A = new $iw.this.A(a, b);
<synthetic> def copy$default$1: String = A.this.a;
<synthetic> def copy$default$2: Option[String] = scala.Some.apply[String](A.this.b)
};
<synthetic> object A extends AnyRef {
def <init>(): A.type = {
A.super.<init>();
()
};
<synthetic> def <init>$default$2: Option[String] = scala.None
}
烨。
scala> def y = "hi"
y: String
scala> def g(x: String)(y: Option[String] = Some(x)) = y map (_ * 2)
g: (x: String)(y: Option[String])Option[String]
scala> g("bye")()
res0: Option[String] = Some(byebye)
scala> def g(x: String)(y: Option[String] = Some(y)) = y map (_ * 2)
<console>:11: error: type mismatch;
found : Option[String]
required: String
def g(x: String)(y: Option[String] = Some(y)) = y map (_ * 2)
^
编辑:默认方法正确的事实并不重要,因为有一些与默认方法不太卫生相关的益智游戏。例如,http://scalapuzzlers.com/#pzzlr-051
答案 1 :(得分:-1)
您的理解是正确的,当存在与周围类型成员同名的参数时,编译器将首选该参数。
在您的非编译版本中,b
的类型为Option[String]
。这意味着Some(b)
的类型为Option[Option[String]]
,它与A
的构造函数的第二个参数的类型不匹配。
在第二个编译版本中,b
仍为Option[String]
类型。但是,b.getOrElse("")
的类型为String
。这意味着Some(b.getOrElse(""))
的类型Option[String]
对A
的第二个构造函数参数有效。