模式匹配组件 'x' 被限制为 isInstanceOf[List[Any]] - 但不能将 'x' 视为 RHS 上的该类型
pattern match component 'x' is constrained to be isInstanceOf[List[Any]] - but can't treat 'x' as that type on RHS
为了熟悉 Scala 列表,我决定实现 flatten
,它将采用如下列表:List(List(2,4), 22, List(1))
到 List(2, 4, 22, 1)
。
当我尝试运行下面的代码时
def flatify(xs: List[Any]) : List[Any] = {
xs match {
case Nil=> {
Nil
}
case x::rest if x.isInstanceOf[List[Any]] => {
flatify(x):: flatify(rest) // bad line
}
case x::rest => {
x:: flatify(rest)
}
case _ => {
throw new IllegalStateException("cant match")
}
}
}
var list = List(List(4, 5), 9, 10, List(1, 2))
flatify(list)
编译器抱怨注释为“// bad line”的行,说:
Error:(84, 17) type mismatch;
found : Any
required: List[Any]
flatify(x):: flatify(rest)
^
这让我觉得很奇怪,因为我的警卫条件明确
要求 x
为 isInstanceOf[List[Any]]
。我明白那个
Any
是 List[Any]
的超类,但我认为
一旦编译器到达表达式的右侧
flatify(x) :: flatify(rest)
它会接受 x
是 List[Any]
。
我确定我的实施可能有其他问题,因为我没有
还没有完全调试它,但在我继续之前我想尝试
了解 Scala 编译器在这里做什么。任何提示或
不胜感激。
Scala 的类型系统(就像 Java 的一样)不会更改 if 中变量的类型,即使 if 条件是 isInstanceOf
。有两种方法可以使您的代码正常工作:
Java 方法是使用强制转换告诉 Scala 在使用 isInstanceOf
.[=17= 检查它确实是一个列表后,可以将 x 用作列表]
Scala 的方法是根本不使用 isInstanceOf
,而是在你的模式中使用 x : List[Any]
, 使静态类型成为x
List[Any]
,所以 x
可以用作没有强制转换的列表。
您正在匹配List[Any]
,所以当您有
case x :: tail if(x.isInstanceOf[List[Any]]) => x ...
^ ^ ^
Any true, but the type of Still Any
x is already determined
x
是 Any
而 tail
是 List[Any]
。 if
条件不会改变 x
的类型,即使您可以测试 x.isInstanceOf[List[Any]]
,x
仍然是 Any
。您需要匹配类型本身。
def flatify(xs: List[Any]) : List[Any] = {
xs match {
case Nil => Nil
case (x: List[Any]) :: rest => flatify(x) ::: flatify(rest)
case x :: rest => x :: flatify(rest)
case _ => throw new IllegalStateException("cant match")
}
}
此外,还有一个bug。给定 x
正确匹配为 List[Any]
,下面的 flatify(x) :: flatify(rest)
会将 List[Any]
放在 List[Any]
的开头,因此根本不会展平。所以我把它改成 :::
.
scala> flatify(List(1,2,3,List(4,5,6), List(7,8,9)))
res1: List[Any] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
为了熟悉 Scala 列表,我决定实现 flatten
,它将采用如下列表:List(List(2,4), 22, List(1))
到 List(2, 4, 22, 1)
。
当我尝试运行下面的代码时
def flatify(xs: List[Any]) : List[Any] = {
xs match {
case Nil=> {
Nil
}
case x::rest if x.isInstanceOf[List[Any]] => {
flatify(x):: flatify(rest) // bad line
}
case x::rest => {
x:: flatify(rest)
}
case _ => {
throw new IllegalStateException("cant match")
}
}
}
var list = List(List(4, 5), 9, 10, List(1, 2))
flatify(list)
编译器抱怨注释为“// bad line”的行,说:
Error:(84, 17) type mismatch;
found : Any
required: List[Any]
flatify(x):: flatify(rest)
^
这让我觉得很奇怪,因为我的警卫条件明确
要求 x
为 isInstanceOf[List[Any]]
。我明白那个
Any
是 List[Any]
的超类,但我认为
一旦编译器到达表达式的右侧
flatify(x) :: flatify(rest)
它会接受 x
是 List[Any]
。
我确定我的实施可能有其他问题,因为我没有 还没有完全调试它,但在我继续之前我想尝试 了解 Scala 编译器在这里做什么。任何提示或 不胜感激。
Scala 的类型系统(就像 Java 的一样)不会更改 if 中变量的类型,即使 if 条件是 isInstanceOf
。有两种方法可以使您的代码正常工作:
Java 方法是使用强制转换告诉 Scala 在使用 isInstanceOf
.[=17= 检查它确实是一个列表后,可以将 x 用作列表]
Scala 的方法是根本不使用 isInstanceOf
,而是在你的模式中使用 x : List[Any]
, 使静态类型成为x
List[Any]
,所以 x
可以用作没有强制转换的列表。
您正在匹配List[Any]
,所以当您有
case x :: tail if(x.isInstanceOf[List[Any]]) => x ...
^ ^ ^
Any true, but the type of Still Any
x is already determined
x
是 Any
而 tail
是 List[Any]
。 if
条件不会改变 x
的类型,即使您可以测试 x.isInstanceOf[List[Any]]
,x
仍然是 Any
。您需要匹配类型本身。
def flatify(xs: List[Any]) : List[Any] = {
xs match {
case Nil => Nil
case (x: List[Any]) :: rest => flatify(x) ::: flatify(rest)
case x :: rest => x :: flatify(rest)
case _ => throw new IllegalStateException("cant match")
}
}
此外,还有一个bug。给定 x
正确匹配为 List[Any]
,下面的 flatify(x) :: flatify(rest)
会将 List[Any]
放在 List[Any]
的开头,因此根本不会展平。所以我把它改成 :::
.
scala> flatify(List(1,2,3,List(4,5,6), List(7,8,9)))
res1: List[Any] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)