Pau*_*rey 2 scala type-inference
根据下面的示例,调用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))
Run Code Online (Sandbox Code Playgroud)
看的定义toBuffer和toList:
def toBuffer[A1 >: A]: Buffer[A1]
def toList: List[A]
Run Code Online (Sandbox Code Playgroud)
如您所见,toBuffer是通用的,而toList不是.造成这种差异的原因是 - 我相信 - 这Buffer是不变的,而且List是协变的.
假设我们有以下类:
class Foo
class Bar extends Foo
Run Code Online (Sandbox Code Playgroud)
因为List是协变的,你可以调用toList一个实例Iterable[Bar]并将结果视为一个List[Foo].如果List在哪里不变,那就不是这种情况.
Buffer是不变的,如果toBuffer定义为def toBuffer: Buffer[A]你同样不能将toBuffer(在一个实例上Iterable[Bar])的结果视为一个实例Buffer[Foo] (因为Buffer[Bar]它不是一个子类型Buffer[Foo],不像列表).但是通过声明toBuffer为def toBuffer[A1 >: A](注意添加的类型参数A1),我们回到了toBuffer返回一个实例的可能性Buffer[Foo]:我们需要的只是explcitly设置A1为Foo,或者让编译器推断它(如果toBuffer在a的网站上调用它Buffer[Foo])预期).
我认为这解释了原因toList和toBuffer定义不同的原因.现在问题在于它toBuffer是通用的,这可能会严重影响推理.
当你这样做:
"ab-cd".split("-").toBuffer
Run Code Online (Sandbox Code Playgroud)
你从来没有明确地说,A1是String的,但因为"ab-cd".split("-")有明确的类型Array[String],编译器知道A是String.它也知道A1 >: A(in toBuffer),并且没有任何进一步的约束,换句话说,它将推断A1为确切的.所以最后整个表达式返回一个.AStringBuffer[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]需要知道确切类型的A和R,就像任何泛型类型一样).所以你需要以某种方式告诉他,因为它无法完全推断出来.
这意味着您需要执行以下任一操作:
"ab-cd".split("-").toBuffer[String].map(_.toBuffer)
Run Code Online (Sandbox Code Playgroud)
要么:
"ab-cd".split("-").toBuffer.map((_:String).toBuffer)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
300 次 |
| 最近记录: |