我有一个函数的用例,它针对任何TraversableOnce[T]
T
的任何类型进行参数化。我试着用
def test[T, F[_] <: TraversableOnce[_]](ts: F[T]): Unit = {
ts.foldLeft("")((acc: String, t: T) => if (acc.isEmpty) t.toString else acc + "," + t.toString)
}
但Scalac以一种我发现奇怪的方式抱怨:
<console>:8: error: type mismatch;
found : (String, T) => String
required: (String, _$1) => String
ts.foldLeft("")((acc: String, t: T) => if (acc.isEmpty) t.toString else acc + "," + t.toString)
现在我知道我可以使用约束F[T] <: TraversableOnce[T]
,但我想理解为什么Scalac无法使用我刚刚编写的函数版本。 ts
的类型为F[T]
,因此foldLeft
的第二个参数的类型应为(String, T) => String
而(String, _$1) => String
的{{1}}的类型未知。这里发生了什么?
答案 0 :(得分:3)
这样的签名:
def test[T, F[_] <: TraversableOnce[_]](ts: F[T]): Unit
与此类签名不同:
def test[T, F[X] <: TraversableOnce[X]](ts: F[T]): Unit
在后一种情况下,你说F“F是一个带有单一类型参数的类型,它是TraversableOnce的子类,只要F和TraversableOnce具有相同的类型参数。”带下划线的版本意味着更像“F是具有单个参数的类型,它是TraversableOnce [Any]的子类”。
意义不同的原因是第一个版本中的两个下划线是不相关的。在该签名中,TraversableOnce[_]
与TraversableOnce[Any]
相同,而在F[_]
中,下划线充当自由变量。这相当于这样说:
def test[T, F[X] <: TraversableOnce[_]](ts: F[T]): Unit
此处,X
是一个自由变量,不会绑定到F[X]
之外的任何内容。
答案 1 :(得分:1)
您尚未将类型参数绑定到可遍历的类型参数。
您正在传递一个需要T
的函数,但是不会限制遍历的未知类型参数。
scala> def f[T, F[T] <: TraversableOnce[T]](ts: F[T]) = ts.foldLeft("") _
f: [T, F[T] <: TraversableOnce[T]](ts: F[T])((String, T) => String) => String
scala> def f[T, F[_] <: TraversableOnce[_]](ts: F[T]) = ts.foldLeft("") _
f: [T, F[_] <: TraversableOnce[_]](ts: F[T])((String, Any) => String) => String
符号TO[_]
是TO[t] forSome { type t }
的简写,其中_$1
是您可遍历的t
。