我试图为排序函数创建一个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