在scala 3中,如何为Iteratable和Array这样的东西获得一个给定的工厂?



我试图为排序函数创建一个trait:

trait Sorting:
def sort[A, B >: A, C <: IterableOnce[A]](list: C)(using ord: Ordering[B], factory: Factory[A, C]): C

,下面是实现:

object InsertionSorting extends Sorting:
override def sort[A, B >: A, C <: IterableOnce[A]](list: C)(using ord: Ordering[B], factory: Factory[A, C]): C =
list.iterator
.foldLeft(ListBuffer.empty[A]) { (acc, x) =>
{
val index = acc.view.takeWhile(y => ord.lt(y, x)).size
acc.insert(index, x)
acc
}
}
.to(factory)

With a test:

class InsertionSortingSpec extends AnyFlatSpec with should.Matchers:
"A Sorting" should "sort correctly" in {
val sorting: Sorting = InsertionSorting
val input = Seq(31, 41, 59, 26, 41, 58)
val actual = sorting.sort(input)
actual shouldBe sorted
}

它工作,到目前为止一切顺利。

但是当我试图用数组

替换测试中的输入时
class InsertionSortingSpec extends AnyFlatSpec with should.Matchers:
"A Sorting" should "sort correctly" in {
val sorting: Sorting = InsertionSorting
val input = Array(31, 41, 59, 26, 41, 58)
val actual = sorting.sort(input)
actual shouldBe sorted
}

编译失败:

[error] 11 |    val actual = sorting.sort(input)
[error]    |                                    ^
[error]    |no implicit argument of type collection.Factory[A, scala.collection.mutable.ArraySeq.ofInt] was found for parameter factory of method sort in trait Sorting
[error]    |
[error]    |where:    A is a type variable with constraint >: Int

所以我必须在Sorting中为Array添加另一个方法:

trait Sorting:
def sort[A, B >: A, C <: IterableOnce[A]](list: C)(using ord: Ordering[B], factory: Factory[A, C]): C
def sort[A: ClassTag, B >: A](array: Array[A])(using Ordering[B]): Array[A] =
sort(array.iterator).toArray[A]

它又工作了。我知道。

我只是想知道我们有没有办法用一种方法来完成它?

BTW,to方法对于IterableOnce,为什么参数factory不是隐式的?

def to[C1](/*using*/ factory: Factory[A, C1]): C1

2022-06-09

更新根据正确答案,我重写如下:

object InsertionSorting extends Sorting:
override def sort[A, B >: A: Ordering, C](
xs: C
)(using view: C => IterableOnce[A], factory: Factory[A, C])(using ClassTag[A]): C =
import math.Ordered.orderingToOrdered
view(xs).iterator
.foldLeft(ListBuffer.empty[A]) { (acc, x) =>
{
val index = acc.view.takeWhile(_ < x).size
acc.insert(index, x)
acc
}
}
.to(factory)

只需添加一些语法糖(Context Bounds, Given Imports)

这个怎么样:

Welcome to Scala 3.1.3-RC3 (17.0.3.1, Java Java HotSpot(TM) 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> import scala.reflect.ClassTag
scala> import scala.collection.mutable.ListBuffer
scala> import scala.collection.Factory
scala> object InsertionSorting:
|   def sort[C, A](list: C)(using view: C => IterableOnce[A], tag: ClassTag[A], factory: Factory[A, C], ord: Ordering[A]): C =
|     view(list).iterator
|       .foldLeft(ListBuffer.empty[A]) { (acc, x) =>
|         {
|           val index = acc.view.takeWhile(y => ord.lt(y, x)).size
|           acc.insert(index, x)
|           acc
|         }
|       }
|       .to(factory)
|
// defined object InsertionSorting
scala> InsertionSorting.sort(Array(3, 4, 5, 9, 1, 2))
val res0: Array[Int] = Array(1, 2, 3, 4, 5, 9)
scala> InsertionSorting.sort(List(3, 4, 5, 9, 1, 2))
val res1: List[Int] = List(1, 2, 3, 4, 5, 9)
scala> InsertionSorting.sort(Seq(3, 4, 5, 9, 1, 2))
val res2: Seq[Int] = List(1, 2, 3, 4, 5, 9)
scala> InsertionSorting.sort("abcABC123")
val res3: String = 123ABCabc

相关内容

  • 没有找到相关文章

最新更新