带有隐式排序的类的Scala集合

问题描述 投票:0回答:2

我想创建一个Array(或List,ArrayBuffer等),它只能包含具有已定义隐式排序的类的实例(例如Int,Long,Double)。

像这样的东西:

val ab = new ArrayBuffer[???]()
ab += 7
ab += 8.9
ab += 8L

我不想将这些值相互比较。

scala collections implicit
2个回答
1
投票

只需使用类型类约束,如下所示

def createList[T: Ordering](values: T*) = values.toList

T: Ordering暗示只允许将范围内的Ordering实例作为参数传递给函数的类型。

scala> def createList[T: Ordering](values: T*) = values.toList
createList: [T](values: T*)(implicit evidence$1: Ordering[T])List[T]

scala> case class Cat()
defined class Cat

scala> createList(1, 2, 3)
res2: List[Int] = List(1, 2, 3)

scala> createList(Cat())
<console>:15: error: No implicit Ordering defined for Cat.
       createList(Cat())
             ^

范围内提供整数排序,但范围内不提供猫排序。因此,在提供Cat的实例之前,您无法传递Ordering[Cat]

现在让我们提供一些假订单,看看编译器是否接受Cat作为参数

scala> implicit val orderingCat: Ordering[Cat] = (a: Cat, b: Cat) => ???
orderingCat: Ordering[Cat] = $anonfun$1@6be766d1

scala> createList(Cat())
res4: List[Cat] = List(Cat())

有用。


0
投票

如果你真的想拥有一个不同类型的对象列表,并且仍然能够在编译时静态检查该列表中的对象,那么你必须使用类似HListshapeless。下面是一个示例,说明如何使用两个异构列表并在编译时检查两个列表中的每个第i个元素是否可以相互比较。

import shapeless._
import shapeless.ops.hlist.{LiftAll, Zip, Mapper}

object lt extends Poly1 { 
  implicit def instance[A] = at[(Ordering[A], A, A)] { 
    case (ord, a, b) => ord.lt(a, b)
  } 
}

def areLessThan[L <: HList, O <: HList, OLL <: HList](a: L, b: L)(
  implicit 
  ord: LiftAll.Aux[Ordering, L, O], 
  zip: Zip.Aux[O :: L :: L :: HNil, OLL], 
  map: Mapper[lt.type, OLL]
) = zip(ord.instances :: a :: b :: HNil).map(lt)

使用它:

scala> val a = 1 :: "b" :: Option(4L) :: HNil
a: Int :: String :: Option[Long] :: shapeless.HNil = 1 :: b :: Some(4) :: HNil

scala> val b = 2 :: "a" :: Option(7L) :: HNil
b: Int :: String :: Option[Long] :: shapeless.HNil = 2 :: a :: Some(7) :: HNil

scala> areLessThan(a, b)
res10: Boolean :: Boolean :: Boolean :: shapeless.HNil = true :: false :: true :: HNil
© www.soinside.com 2019 - 2024. All rights reserved.