【问题标题】:Scala collection of classes with Implicit Ordering具有隐式排序的 Scala 类集合
【发布时间】:2018-06-04 05:36:28
【问题描述】:

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

类似这样的:

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

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

【问题讨论】:

  • 您是否真的想将不同类型的单个集合对象放入其中,只要每种类型都有一些Ordering[T]?例如,如果每个组件都有排序,则元组有排序。那么将元组(1.0, "some string") 添加到您的ab 是否可以,因为它与您列出的其他值根本无法比较?以后你会如何使用这样的ab?当您通过某个索引从ab 中获取值时,您希望得到什么类型?
  • 我将有一个这样的ab-s 数组,并且我想比较例如 all 的第一个值 - 假定所有第一个元素都具有相同的类型。
  • 您可能想考虑使用HList

标签: scala collections implicit


【解决方案1】:

如果您真的想要一个不同类型的对象列表,并且仍然能够在编译时静态检查该列表中的对象,您将不得不使用来自shapelessHList 之类的东西。这是一个示例,说明如何拥有两个异构列表,并在编译时检查两个列表的每个 ith 元素是否可以相互比较。

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

【讨论】:

    【解决方案2】:

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

    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

    现在让我们提供一些虚假的排序,看看编译器是否接受 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())
    

    有效。

    【讨论】:

    • 不幸的是,如果您想将 CatDouble 存储在同一个数组中,它将不起作用。例如,当您想将 IntString 存储在同一个数组中时,它将查找它们共同超类型的隐式排序,即 Any,没有为其定义隐式排序。
    • @DánielBerecz 如果没有请提供订单。
    猜你喜欢
    • 1970-01-01
    • 2014-11-02
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 1970-01-01
    • 2018-08-16
    • 2012-01-04
    • 2017-05-17
    相关资源
    最近更新 更多