Scala是意外的类型行为

时间:2012-08-27 01:15:27

标签: scala types

为什么这个代码段没有打印出来:“您成功实现了功能”

详细说明:

为什么val实际的类型看起来是List [[[[Int],Int]]类型,当我甚至明确地向编译器说明实际的类型应该是List [Int]类型? / p>

// Flatten a nested list structure

def flatten[T](list: List[Either[List[T], T]]): List[T] = list flatMap {
    // TODO: Implement
    case list: List[T]  => list
    case element: T     => List(element)
}

implicit def ElementToEitherLeft[T](obj: T) = Left(obj)
implicit def ElementToEitherRight[T](obj: T) = Right(obj)

val list: List[Either[List[Int], Int]] = List(List(1, 1), 2, List(3, 5))
val actual: List[Int] = flatten[Int](list)
val expected = List(1, 1, 2, 3, 5)
if (actual == expected)     print("You successfully implemented the function")
else                        print("Unfortunatly, that's not quite rigth yet")

2 个答案:

答案 0 :(得分:7)

编译flatten时,你应该看到这样的警告:

warning: there were 2 unchecked warnings; re-run with -unchecked for details

如果您随后使用-unchecked编译,则会看到:

<console>:9: warning: non variable type-argument T in type pattern List[T] is unchecked since it is eliminated by erasure
           case list: List[T]  => list
                      ^
<console>:10: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure
           case element: T     => List(element)

简而言之,flatMap不会为您打开Either项目,而您编写的内容只会因为类型擦除和模式匹配的一些令人不快的事实而编译。

幸运的是,这是一个简单的解决方法:

 def flatten[T](list: List[Either[List[T], T]]): List[T] = list flatMap {
   case Left(list)  => list
   case Right(item) => item :: Nil
 }

或者,甚至更好:

def flatten[T](list: List[Either[List[T], T]]): List[T] =
  list.flatMap(_.fold(identity, List(_)))

要么按预期工作。

答案 1 :(得分:1)

如果使用2.10编译,您将看到如下警告:

<console>:7: warning: match may not be exhaustive.
It would fail on the following inputs: Left(_), Right(_)

如果使用2.10-M6进行编译,您还会看到如下虚假警告:

warning: unreachable code
case element: T     => List(element)

您希望看到的警告如下:

warning: unreachable code
case list: List[T]  => list

所以你可以意识到你对你给flatMap的函数发生了什么的误解,即哦,它是一个List [Either]而不是List [List],但这是编译器目前做得最好的

这些是在-Xno-patmat-analysis下关闭的警告。似乎没有选择将其提升到11个。

你可以通过删除类型参数来消除你的删除警告,这是很自然的事情,然后你就得不到类型系统的支持,也没有可达性或匹配警告:

def flatten(list: List[Either[List[_], _]]): List[Any] = list flatMap {
  case list: List[_]  => list
  case element        => List(element)
}