模式匹配组件 '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)
                    ^

这让我觉得很奇怪,因为我的警卫条件明确 要求 xisInstanceOf[List[Any]]。我明白那个 AnyList[Any] 的超类,但我认为 一旦编译器到达表达式的右侧

flatify(x) :: flatify(rest)

它会接受 xList[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

xAnytailList[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)