可以使用隐式消除重载定义的歧义吗? [英] Can implicits be used to disambiguate overloaded definition?

查看:112
本文介绍了可以使用隐式消除重载定义的歧义吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑方法mean的以下重载定义:

Consider the following overloaded definition of method mean:

def mean[T](data: Iterable[T])(implicit number: Fractional[T]): T = {
  import number._
  val sum = data.foldLeft(zero)(plus)
  div(sum, fromInt(data.size))
}

def mean[T](data: Iterable[T])(implicit number: Integral[T]): Double = {
  import number._
  val sum = data.foldLeft(zero)(plus)
  sum.toDouble / data.size
}

我希望第二个定义返回Double仅用于Integral类型的情况下

I would like second definition which returns Double only to be used in the case of Integral types, however

mean(List(1,2,3,4))

导致编译器错误

Error: ambiguous reference to overloaded definition,
both method mean in class A$A16 of type [T](data: Iterable[T])(implicit number: Integral[T])Double
and  method mean in class A$A16 of type [T](data: Iterable[T])(implicit number: Fractional[T])T
match argument types (List[Int])
mean(List(1,2,3,4))
^

有没有办法使用Fractional[Int]隐式不可用的事实来消除两个重载的歧义?

Is there any way to use the fact that Fractional[Int] implicit is not available in order to disambiguate the two overloads?

推荐答案

Scala仅考虑 overload 分辨率的第一个参数列表,根据

Scala only considers the first argument list for the overload resolution, according to the specification. Both mean methods are deemed equally specific and ambiguous.

但是对于隐式分辨率,还考虑了范围内的隐式,因此一种解决方法是使用磁模式或类型类.这是一个使用磁铁图案的示例,我认为它更简单:

But for implicit resolution the implicits in scope are also considered, so a workaround could be to use a magnet pattern or a type class. Here is an example using the magnet pattern, which I believe is simpler:

def mean[T](data: MeanMagnet[T]): data.Out = data.mean

sealed trait MeanMagnet[T] {
  type Out
  def mean: Out
}

object MeanMagnet {
  import language.implicitConversions

  type Aux[T, O] = MeanMagnet[T] { type Out = O }

  implicit def fromFractional[T](
    data: Iterable[T]
  )(
    implicit number: Fractional[T]
  ): MeanMagnet.Aux[T, T] = new MeanMagnet[T] {
    override type Out = T

    override def mean: Out = {
      import number._
      val sum = data.foldLeft(zero)(plus)
      div(sum, fromInt(data.size))
    }
  }

  implicit def fromIntegral[T](
    data: Iterable[T]
  )(
    implicit number: Integral[T]
  ): MeanMagnet.Aux[T, Double] = new MeanMagnet[T] {
    override type Out = Double

    override def mean: Out = {
      import number._
      val sum = data.foldLeft(zero)(plus)
      sum.toDouble / data.size
    }
  }
}

使用此定义,它可以正常工作:

With this definition it works normally:

scala> mean(List(1,2,3,4))
res0: Double = 2.5

scala> mean(List(1.0, 2.0, 3.0, 4.0))
res1: Double = 2.5

scala> mean(List(1.0f, 2.0f, 3.0f, 4.0f))
res2: Float = 2.5   

这篇关于可以使用隐式消除重载定义的歧义吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆