在 scala List :: 中不进行隐式转换

In scala List :: doesn't do implicit conversion

在 scala 中,可以在 Seq 中转换一个变量,但是如果我用 :: 构造 Seq 它就不起作用了。 例如

  case class A(s: String)
  implicit def toA(s: String): A = A(s)

  val Seq(a, b, c, d): Seq[A] = Seq("a", "b", "c", "d") // compiles
  val Seq(e, f): Seq[A] = "e" :: "f" :: Nil             // won't compile

Seq("a","b","c","d") 实际上是 Seq.apply[X]("a","b","c","d"),其中 X 被推断为左侧的 A。并且在 Seq.apply[A](... 中预期类型为 A 的元素,因此字符串通过 toA 隐式转换为 A(所以它实际上是 val Seq(a, b, c, d): Seq[A] = Seq.apply[A](A("a"), A("b"), A("c"), A("d")))。

"e" :: "f" :: Nil 实际上是 ::[Y]("e", ::[Z]("f", Nil)),其中首先 Z 被推断为 >: String,其次 Y 被推断为 >: String所以它是 >: List[String] 类型(实际上是 List[Serializable])并且它不匹配类型模式 Seq[A]。所以有编译错误。

基本上是从 StringA 而不是从 Seq[String]Seq[A] 的隐式转换。

如果你只写 val Seq(e,f) = "e" :: "f" :: Nil 那么这会编译,因为右侧匹配左侧的模式。

也可以编译 val Seq(f): Seq[A] = "f" :: Nil,因为在 ::[Z]("f", Nil) 中只有一个类型参数,可以推断它等于 A.

这里的问题是编译器没有理由应用隐式转换,直到为时已晚。表达式

"e" :: "f" :: Nil 

创建了一个 List[String],它与导致错误的 Seq[A] 不兼容。

要解决此问题,您需要进行从 List[String]List[A] 的隐式转换。

请注意,此 也不起作用

"e" :: "f" :: List[A]()

您可以将 String 添加到 List[A],这样它就不会隐式转换为 A,您最终会得到 List[Serializable]