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

huangapple go评论71阅读模式
英文:

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)可以工作)。

有人能帮我解释一下吗?肯定有一种方法可以实现我想要的效果,但我无法找到正确的方法 如何在Scala 2.13中正确使用集合工厂?


<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((&quot;foo&quot;,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&#39;t use it, because I don&#39;t have that implicit in scope at the call site (even `swap(Seq)` does&#39;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&#39;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)] &lt;:&lt; 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&#39;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)] &lt;:&lt; 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&#39;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&#39;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 =&gt; a -&gt; a.toString).to(Map)` which eliminated the need for `CanBuildFrom` and separate syntax for `.to[Coll]` and `.toMap`.

</details>



huangapple
  • 本文由 发表于 2023年8月5日 05:55:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76839289.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定