1

为什么这个片段没有打印出来:“你成功地实现了这个功能”

细节:

为什么 val actual 的类型似乎是 List[Either[List[Int], Int]] 类型,而我什至明确对编译器说实际的类型应该是 List[Int] 类型?

// 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")
4

2 回答 2

7

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

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

如果你用 with 编译-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(_)))

两者都将按您的预期工作。

于 2012-08-27T01:45:35.750 回答
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。似乎没有将其调高至十一点的选项。

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

def flatten(list: List[Either[List[_], _]]): List[Any] = list flatMap {
  case list: List[_]  => list
  case element        => List(element)
}
于 2012-08-27T09:45:06.253 回答