gpt4 book ai didi

scala - toList 和 toBuffer 之间的类型推断不一致

转载 作者:行者123 更新时间:2023-12-04 01:40:50 26 4
gpt4 key购买 nike

根据下面的示例,调用 xs.toList.map(_.toBuffer) 成功,但 xs.toBuffer.map(_.toBuffer) 失败。但是,当使用中间结果执行后者的步骤时,它会成功。是什么原因导致这种不一致呢?

scala> "ab-cd".split("-").toBuffer
res0: scala.collection.mutable.Buffer[String] = ArrayBuffer(ab, cd)

scala> res0.map(_.toBuffer)
res1: scala.collection.mutable.Buffer[scala.collection.mutable.Buffer[Char]] = ArrayBuffer(ArrayBuffer(a, b), ArrayBuffer(c, d))

scala> "ab-cd".split("-").toBuffer.map(_.toBuffer)
<console>:8: error: missing parameter type for expanded function ((x$1) => x$1.toBuffer)
"ab-cd".split("-").toBuffer.map(_.toBuffer)
^

scala> "ab-cd".split("-").toList.map(_.toBuffer)
res3: List[scala.collection.mutable.Buffer[Char]] = List(ArrayBuffer(a, b), ArrayBuffer(c, d))

最佳答案

查看 toBuffer 的定义和toList :

def toBuffer[A1 >: A]: Buffer[A1]
def toList: List[A]

如您所见,toBuffer是通用的,而 toList不是。我相信,造成这种差异的原因是 Buffer是不变的,而 List是协变的。

假设我们有以下类:

class Foo
class Bar extends Foo

因为List是协变的,可以调用toListIterable[Bar] 的实例上并将结果视为 List[Foo] 。如果List如果不变,则情况并非如此。 Buffer不变,如果 toBuffer被定义为def toBuffer: Buffer[A]您同样无法处理结果的toBuffer (在 Iterable[Bar] 的实例上)作为 Buffer[Foo] 的实例(因为 Buffer[Bar] 不是 Buffer[Foo] 的子类型,与列表不同)。但通过声明 toBufferdef toBuffer[A1 >: A] (注意添加的类型参数 A1 ),我们得到 toBuffer 的可能性返回 Buffer[Foo] 的实例:我们需要的只是明确设置 A1到 Foo,或者让编译器推断它(如果在需要 toBuffer 的站点上调用 Buffer[Foo])。

我认为这解释了 toList 的原因和toBuffer定义不同。现在的问题是toBuffer是通用的,这会严重影响推理。

当你这样做时:

"ab-cd".split("-").toBuffer

你从来没有明确说过A1String ,但是因为"ab-cd".split("-")类型明确 Array[String] ,编译器知道 AString 。它还知道A1 >: A (在 toBuffer 中),并且没有任何进一步的约束,它将推断 A1确切地说A ,换句话说String 。所以最后整个表达式返回 Buffer[String] .

但事情是这样的:在 scala 中,类型推断发生在整个表达式中。当你有类似 a.b.c 的东西时,您可能期望 scala 会推断出确切的类型对于 a ,然后从中推断出 a.b 的确切类型,最后为a.b.c 。并非如此。类型推断推迟到整个表达式 a.b.c (参见scala规范“6.26.4局部类型推断", "案例1:选择")

那么,回到你的问题,在表达式 "ab-cd".split("-").toBuffer.map(_.toBuffer) 中,子表达式 "ab-cd".split("-").toBuffer 输入 Buffer[String] , 但反而它的输入格式类似于 Buffer[A1] forSome A1 >: String 。换句话说,A1不是固定的,我们只是带有约束 A1 >: String到下一步的推理。下一步是map(_.toBuffer) ,其中map定义为map[C](f: (B) ⇒ C): Buffer[B] 。这里B实际上与 A1 相同,但此时A1目前还不完全清楚,我们只知道A1 >: String 。我们的问题就在这里。编译器需要知道匿名函数的确切类型 (_.toBuffer) (仅仅因为实例化 Function1[A,R] 需要知道 AR 的确切类型,就像任何泛型类型一样)。所以你需要以某种方式明确地告诉他,因为它无法准确地推断出来。

这意味着您需要执行以下任一操作:

"ab-cd".split("-").toBuffer[String].map(_.toBuffer)

或者:

"ab-cd".split("-").toBuffer.map((_:String).toBuffer)

关于scala - toList 和 toBuffer 之间的类型推断不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30659545/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com