英文:
How to properly use collection factories in scala 2.13?
问题
Here is the translated code snippet:
隐式类 PairOps[A, B, C[X] <: Iterable[X]](val c: C[(A, B)]) extends AnyVal {
def swap = c.map { case (a, b) => (b, a) }
}
And the second part:
怎么修复它?在2.12版本中有一个叫做`breakOut`的方法,使用了一些我从未完全理解的魔法来执行这种操作,但现在我需要一个`Factory`。
尝试将它添加为隐式参数:
```scala
def swap(implicit f: Factory[(B, A), C]) = c.map { case (a, b) => (b, a) }.to(f)
这将以正确的类型编译,但我无法使用它,因为在调用位置没有该隐式参数(即使swap(Seq)
也无法正常工作,尽管在第一个版本中不带隐式工厂的情况下swap.to(Seq)
可以工作)。
有人能帮我解释一下吗?肯定有一种方法可以实现我想要的效果,但我无法找到正确的方法
<details>
<summary>英文:</summary>
Something like this:
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) }
}
Kinda works ... except that `val foo: Seq[(Int, String)] = Seq(("foo",1)).swap` does not compile, because `swap` returns `Iterable` rather than a `Seq`.
How do I fix it? There used to be `breakOut` in 2.12 that was using some magic (that I never quite understood tbh) to do this kind of thing ... but now I need a `Factory` ...
Tried adding it as an implicit param:
def swap(implicit f: Factory[(B,A),C]) = c.map { case (a,b) => (b,a) }.to(f) }
This compiles with the right type, but I can't use it, because I don't have that implicit in scope at the call site (even `swap(Seq)` does't work for some reason, even though `swap.to(Seq)` does (in the first version, without implicit factory) ...
Can someone please set me straight here? There must be a way to accomplish what I want here, but I can't figure out the right incantation :(
</details>
# 答案1
**得分**: 2
以下是已翻译的内容:
Took me a bit of fiddling around and to be very honest I'm not 100% sure of _why_ this works (and if anyone comes along with an explanation you should probably accepts their answer), but it looks like this gets the job done:
需要我花一点时间摆弄,坦白说,我不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)
}
The returned type is the one of the collection wrapped by `PairOps`. You can play around with this code [here on Scastie][1].
返回的类型是由`PairOps`包装的集合类型。您可以在[Scastie上这里](https://scastie.scala-lang.org/stefanobaghino/Yn6tYWBsRpCQri2CNRhwPw)测试此代码。
<details>
<summary>英文:</summary>
Took me a bit of fiddling around and to be very honest I'm not 100% sure of _why_ this works (and if anyone comes along with an explanation you should probably accepts their answer), but it looks like this gets the job done:
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)
}
The returned type is the one of the collection wrapped by `PairOps`. You can play around with this code [here on Scastie][1].
[1]: https://scastie.scala-lang.org/stefanobaghino/Yn6tYWBsRpCQri2CNRhwPw
</details>
# 答案2
**得分**: 2
以下是您要翻译的内容:
```scala
对我有效的是修改你正在获取的隐式:
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](https://scastie.scala-lang.org/MateuszKubuszok/YvZt9j6US1KBCqR08KNsMQ/2)
冗长之处在于在2.13之前使用的“请求 `[A, C[_]]` 并生成 `C[A]`” 方法不适用于想要执行以下操作的情况:
```scala
Factory[(Int, String), Map[Int, String]]
(您可以在2.12中使用 .to(Map)
(例如,使用 scala-collection-compat)时,最终会得到一个Map...被强制转换为 Iterable[(K, V)]
,因为 .to
接口在 [A, Coll[_]]
上运行,为了能够将 Map
工厂传递进去,它必须将其上转换为 Iterable
工厂。)
换句话说,由2.13引入的冗长性允许在像 seq.map(a => a -> a.toString).to(Map)
这样的情况下使用 Factory
,从而消除了对 CanBuildFrom
和 .to[Coll]
以及 .toMap
的单独语法的需求。
<details>
<summary>英文:</summary>
What works for me is modifying the implicit you are fetching:
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
see [Scastie](https://scastie.scala-lang.org/MateuszKubuszok/YvZt9j6US1KBCqR08KNsMQ/2)
The reason for the verbosity is that *ask for `[A, C[_]]` and make `C[A]` out of it* approach which was used prior to 2.13 doesn't work if you want to do e.g.
Factory[(Int, String), Map[Int, String]]
(You can check that in 2.12 when you use `.to(Map)` (e.g with scala-collection-compat) you'll end up with a Map... upcasted to `Iterable[(K, V)]` precisely because `.to` interface operates on `[A, Coll[_]]` and to be able to shove `Map` factory there, it has to upcast it to `Iterable` factory.)
In other words the verbosity added by by 2.13 allows `Factory` to be used in cases like `seq.map(a => a -> a.toString).to(Map)` which eliminated the need for `CanBuildFrom` and separate syntax for `.to[Coll]` and `.toMap`.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论