如何在scala 2.13中正确使用集合工厂?

cfh9epnr  于 9个月前  发布在  Scala
关注(0)|答案(2)|浏览(101)

大概是这样的:

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,它使用了一些魔法(我从来没有完全理解tbh)来做这种事情。但现在我需要一个Factory ...
已尝试将其作为隐式参数添加:

def swap(implicit f: Factory[(B,A),C]) = c.map { case (a,b) => (b,a) }.to(f) }

这可以用正确的类型编译,但是我不能使用它,因为我在调用站点的作用域中没有隐式类型(即使swap(Seq)由于某种原因也不能工作,尽管swap.to(Seq)可以(在第一个版本中,没有隐式工厂)。
有没有人能帮我把话说清楚?一定有一种方法可以达到我的目的,但我想不出正确的咒语:(

gt0wga4j

gt0wga4j1#

对我有用的是修改你正在获取的隐式:

import scala.collection.Factory

implicit class PairOps[A, B, C[X] <: Iterable[X]](val c: C[(A,B)]) extends AnyVal {
   def swap(implicit f: Factory[(B, A), C[(B, A)]]) = c.map { case (a, b) => (b, a) }.to(f)
}

List(1 -> "test").swap

参见Scastie
冗长的原因是,如果你想做,那么在2.13之前使用的 * 请求[A, C[_]]并从中生成C[A] * 的方法就不起作用了。

Factory[(Int, String), Map[Int, String]]

(You可以检查一下,在2.12中,当你使用.to(Map)(例如,使用scala-collection-compat)时,你最终会得到一个Map.上推到Iterable[(K, V)]正是因为.to接口在[A, Coll[_]]上运行,并且为了能够将Map工厂推到那里,它必须上推到Iterable工厂。)
换句话说,在2.13中增加的versity允许Factory用于像seq.map(a => a -> a.toString).to(Map)这样的情况,这消除了对CanBuildFrom的需要,并为.to[Coll].toMap提供了单独的语法。

ekqde3dh

ekqde3dh2#

花了我一点时间,老实说,我不是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 Package 的集合的类型。你可以使用这个代码here on Scastie

相关问题