模式匹配组件';x';被约束为isInstanceOf[List[Any]]——但可以';t治疗';x';就像RHS上的那种

模式匹配组件';x';被约束为isInstanceOf[List[Any]]——但可以';t治疗';x';就像RHS上的那种,list,scala,functional-programming,List,Scala,Functional Programming,为了熟悉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]] => { flat

为了熟悉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)
编译器抱怨该行注释为“//错误行”,并说:

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
是一个
列表[任何]

我相信我的实现可能会有其他问题,因为我没有 已经完全调试过了,但在我继续之前,我想尝试 了解Scala编译器在这里的用途。有什么提示或建议吗 非常感谢指针。

Scala的类型系统(就像Java的一样)不会更改if中变量的类型,即使if条件是
isInstanceOf
。有两种方法可以使代码正常工作:

Java的方法是使用cast告诉Scala,在您使用
isInstanceOf
检查x是否确实是一个列表后,可以使用x作为列表

Scala的方法是根本不使用
isInstanceOf
,而是在模式中使用
x:List[Any]
,这确实使
x
List[Any]
成为静态类型,因此
x
可以作为列表使用,而无需强制转换不更改if内变量的类型,即使if条件为
isInstanceOf
。有两种方法可以使代码正常工作:

Java的方法是使用cast告诉Scala,在您使用
isInstanceOf
检查x是否确实是一个列表后,可以使用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]
如果
条件没有改变
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)

您在
列表[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]
如果
条件没有改变
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)

从您和sepp2k处找到有用的答案。。但既然你甚至用:::修复了我的愚蠢错误,我会接受你的,但要感谢你们两个!从您和sepp2k处找到有用的答案。。但既然你甚至用:::修复了我的愚蠢错误,我会接受你的,但要感谢你们两个!