【问题标题】:scala polymorphic type signatures with Ordering and ClassTag具有 Ordering 和 ClassTag 的 scala 多态类型签名
【发布时间】:2018-10-06 10:08:03
【问题描述】:

我需要帮助理解这种类型签名:

def func[A : Ordering : ClassTag](a: A) = ???

我已经使用上面的类型签名提出了虚拟示例......以及我更熟悉的类型签名,我相信这与基于我的虚拟示例的相同,但我可以还想出了一个玩具例子,它们显然不一样。

这两个看起来很相似:

import scala.reflect.ClassTag

// type signature in question
def func1[A : Ordering : ClassTag](elems: A*) = 
  Array[A](elems: _*).sorted

// my typical type signature
def func2[A <% Ordered[A]](elems: A*)(implicit c: ClassTag[A]) = 
  Array[A](elems: _*).sorted

使用示例:

class BB(val i: Int) extends Ordered[BB] {
  def compare(that: BB): Int = that.i - i
  override def toString = s"BB(${i})"
}

func1(new BB(33), new BB(100), new BB(-1))
func2(new BB(33), new BB(100), new BB(-1))

每个的输出是:

Array[BB] = Array(BB(100), BB(33), BB(-1))

我可以提出它们不同的一个极端情况......表明一个不仅仅是另一种的语法糖......如下,其中函数具有与类不同的类的隐式顺序自然排序顺序。

此示例(如下)运行良好,implicit val ordering 覆盖了我(有点)预期的 BB 类的自然排序顺序。

def func3[A <% Ordered[A] : ClassTag](elems: A*) = {
  // opposite order defined in class BB
  implicit val ordering: Ordering[A] = 
    Ordering.by{ case bb: BB => bb.i }  

  Array[A](elems: _*).sorted
}

这个版本(下)给我报错...

def func3[A : Ordering : ClassTag](elems: A*) = {
  // opposite order defined in class BB
  implicit val ordering: Ordering[A] = 
    Ordering.by{ case bb: BB => bb.i }  

  Array[A](elems: _*).sorted
}

错误:不明确的隐含值:两者都是 Ordering[A] 类型的值 evidence$1 和 Ordering[A] 类型的值排序匹配预期类型 scala.math.Ordering[A]

因此基于此...我猜: OrderingOrdered[BB] 转换为implicit val ordering...或类似的东西?我的玩具示例未能揭示出更深层次的差异吗?

提前致谢。

【问题讨论】:

    标签: scala types polymorphism


    【解决方案1】:

    类型参数后面的: 是隐式参数声明的语法糖。在这种情况下,这意味着

    def func1[A: Ordering: ClassTag](elems: A*) = Array[A](elems: _*).sorted
    

    相同
    def func1[A](elems: A*)(implicit ordering: Ordering[A], classTag: ClassTag[A]) = Array[A](elems: _*).sorted
    

    另一方面,func2 声明了一个从 AOrdered 的视图绑定 (&lt;%)。知道这一点后,编译器可以调用 Ordering[Ordered] 并传递给 sorted 方法

    fun3 的最新版本未编译的原因是因为您在范围内提供了 2 个隐式 Ordering[A]:声明为 fun3 的隐式参数和隐式 val ordering。编译器不知道选择哪一个并且它抱怨它,你应该删除其中一个来修复它。

    无论如何,在这些函数的实现中引入关于特定类型的代码并不是一个好主意。对于不是BB 的任何类型,创建val ordering 的模式匹配都会失败。

    如果您的目标是定义一个特定的Ordering[BB],您可以在 BB 的伴随对象中执行此操作,然后将其加载到调用函数的隐式范围中,如下所示

    class BB(val i: Int) {
      override def toString: String = s"BB(${i})"
    }
    
    object BB {
      implicit val ordering = Ordering.by[BB, Int](_.i)
      val reverseOrdering = Ordering.by[BB, Int](-_.i)
    }
    

    然后,当您尝试订购 BB 时,它会默认选择隐式排序,但您始终可以通过这样做来覆盖它

    implicit val ord = BB.reverseOrdering
    Seq[BB]().sorted
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-27
      • 1970-01-01
      • 2012-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多