类似这样的:
implicit class PairOps[A, B, C[X] <: Iterable[X]](val c: C[(A,B)]) extends AnyVal {
def swap = c.map { case (a, b) => (b, a) }
}
有点有效...除了
val foo: Seq[(Int, String)] = Seq(("foo",1)).swap
无法编译,因为 swap
返回 Iterable
而不是 Seq
。
如何解决? 2.12 中曾经有
breakOut
正在使用一些魔法(说实话,我一直不太理解)来做这种事情......但现在我需要一个 Factory
...
尝试将其添加为隐式参数:
def swap(implicit f: Factory[(B,A),C]) = c.map { case (a,b) => (b,a) }.to(f) }
这可以使用正确的类型进行编译,但我无法使用它,因为我在调用站点的范围内没有隐含的范围(即使
swap(Seq)
出于某种原因也不起作用,尽管 swap.to(Seq)
确实(在第一个版本中,没有隐式工厂)...
有人可以帮我指点一下吗?一定有一种方法可以实现我在这里想要的,但我无法找出正确的咒语:(
我花了一些时间摆弄,说实话,我不是100%确定为什么这有效(如果有人提出解释,你可能应该接受他们的答案),但看起来这得到了工作完成:
implicit class PairOps[A, B, C[X]](val c: C[(A, B)]) extends AnyVal {
def swap(implicit ev: C[(A, B)] <:< collection.IterableOnceOps[(A, B), C, _]): C[(B, A)] =
c.map(_.swap)
}
返回的类型是由
PairOps
包装的集合之一。您可以在 Scastie 上使用此代码。