作为上一个问题的后续,我是否可以设计一个隐式类来处理两种类型的SeqLike
扩展:
import collection.SeqLike
import collection.generic.CanBuildFrom
implicit class Test[A, Repr](val sq: SeqLike[A, Repr]) extends AnyVal {
// no constraints on Repr
def foo[B](f: A => B)(implicit ord: Ordering[B]): Repr = sq.sortBy(f)
// constraint that actually sq is Repr
def bar[B, To](fun: (A, A) => B)(implicit cbf: CanBuildFrom[Repr, B, To]): To = {
val b = cbf(sq) // NO!
// ...
b.result
}
}
bar
方法没有编译,因为我们缺少typeOf(sq) == Repr
的约束。正如其他人所指出的,如果我将构造函数更改为sq: Repr
,我们将失去与类型A
的连接。
现在,Repr
断开连接。例如:
// in Test:
def isSortedBy[B](fun: A => B)(implicit ord: Ordering[B]): Boolean =
sq.sliding(2, 1).forall {
case a +: b +: _ => ord.lteq(fun(a), fun(b))
case _ => true // happens when it size == 1
}
[error] Test.scala: inferred type arguments [T,Equals] do not conform to method
unapply's type parameter bounds
[T,Coll <: scala.collection.SeqLike[T,Coll]]
[error] case a +: b +: _ => ord.lteq(fun(a), fun(b))
[error] ^
您可以使用repr
,并将sq
的类型更改为SeqLike
,而不是Repr
。但与我以前的解决方案不同,您可以将上类型绑定到Repr
(Repr<:SeqLike[A,Repr]
),以解决剩余的键入问题。举例:
implicit class Test[A, Repr<:SeqLike[A,Repr]](val sq: SeqLike[A, Repr]) extends AnyVal {
// no constraints on Repr
def foo[B](f: A => B)(implicit ord: Ordering[B]): Repr = sq.sortBy(f)
// constraint that actually sq is Repr
def bar[B, To](fun: (A, A) => B)(implicit cbf: CanBuildFrom[Repr, B, To]): To = {
val b = cbf(sq.repr) // NO!
var x = sq.head
sq.tail.foreach { y =>
b+=fun(x,y)
x = y
}
b.result
}
def isSortedBy[B](fun: A => B)(implicit ord: Ordering[B]): Boolean =
sq.sliding(2, 1).forall {
case a +: b +: _ => ord.lteq(fun(a), fun(b))
case _ => true // happens when it size == 1
}
}
因此,如果我正确理解问题,
-
如果将类参数
sq
设置为Repr
,则会丢失类型A
(不再有任何推断), -
但如果您将其设置为
SeqLike[A, Repr]
,那么您将失去也是Repr
的事实,因此cbf(sq)
不再编译。
那么两者都做呢:
implicit class Test[A, Repr](val sq: Repr with SeqLike[A, Repr]) extends AnyVal {
...
}
这个版本编译得很好,我可以在一个简单的List(1,2,3)
上调用foo
和bar
。
编辑:如果要将sq
以外的类型Repr
的值作为集合进行操作,还需要Régis的答案中的类型绑定Repr <: SeqLike[A,Repr]
。
sq: Repr with SeqLike[A, Repr]
唯一能给你的是,你可以在任何地方使用sq
而不是sq.repr
,因为它已经被正确地键入了。