隐式视图不起作用 - 我的隐式定义应该受到指责吗?

Implicit view not working - is my implicit def to blame?

我在使用隐式视图时遇到了一些问题。我怀疑这是非常微不足道的,并且可能有一些简单得令人尴尬的答案。我有这样的情况,以及(显然,不成功)调试它的尝试:

abstract class StoresNumeric[A, T: Numeric] {
  def getNum(self: A): T
}
object StoresNumericSyntax {
  implicit class StoresNumericOps[A, T: Numeric](value: A) {
    def getNum(implicit sn: StoresNumeric[A, T]): T = sn.getNum(value)
  }
}
case class ANumber[T: Numeric](
  num: T
)
implicit def aNumberStoresNumeric[T: Numeric] = 
  new StoresNumeric[ANumber[T], T] {
    def getNum(self: ANumber[T]): T = self.num
  }
val a = ANumber[Int](3)
// 1. Works fine, so explicit conversion possible
aNumberStoresNumeric[Int].getNum(a) 
// 2. Works fine, so implicit conversion possible
implicitly[StoresNumeric[ANumber[Int], Int]].getNum(a) 
// 3. Doesn't work, so implicit conversion not working
println(implicitly[ANumber[Int] => StoresNumeric[ANumber[Int], Int]]) // no implicit view available...
// 4. The holy grail. Doesn't work, for the same reason as above, plus possibly other
a.getNum

我认为这里的问题是我的 implicit def,或者更准确地说,我对 implicit def 缺乏理解实际上是为了工作。我不确定泛型扮演什么角色 - 应该使用第一个泛型参数来表示我实际想要转换的类型,还是可以按原样使用?

感谢收到的任何帮助。

首先(#3),

implicitly[ANumber[Int] => StoresNumeric[ANumber[Int], Int]]

错了。您没有定义从数据类型到类型 class 的隐式转换,而是定义了从数据类型到隐式 class 引入扩展方法的隐式转换。所以应该是

implicitly[ANumber[Int] => StoresNumericSyntax.StoresNumericOps[ANumber[Int], Int]]

并编译。

准备好 implicitly[A => B] 并不总是检查是否存在从 AB 的隐式转换。 * (见下文)

其次(#4),当你使用扩展方法(a.getNum)时你应该导入语法对象:

import StoresNumericSyntax._
(a: StoresNumericOps[ANumber[Int], Int]).getNum

编译,而

import StoresNumericSyntax._
a.getNum

生产(scalacOptions += "-Xlog-implicits" 开启)

 Warning:
StoresNumericOps is not a valid implicit value for App.a.type => ?{def getNum: ?} because:
ambiguous implicit values:
 both object BigIntIsIntegral in object Numeric of type scala.math.Numeric.BigIntIsIntegral.type
 and object IntIsIntegral in object Numeric of type scala.math.Numeric.IntIsIntegral.type
 match expected type Numeric[T]

如果您导入 IntIsIntegral,您会将此隐式添加到本地范围(在此之前它仅在隐式范围内),因此您将使其“优先级”“高于” BigIntIsIntegral。尝试

import StoresNumericSyntax._
import Numeric.IntIsIntegral
a.getNum

编译通过。

Scala 2.13.3.

另请参阅如何调试隐式(在编译时):In scala 2 or 3, is it possible to debug implicit resolution process in runtime?


* 例如,如果您将隐式 class 修改为 @LuisMiguelMejíaSuárez 在评论中建议

object StoresNumericSyntax {
  implicit class StoresNumericOps[A](private val value: A) extends AnyVal {
    def getNum[T: Numeric](implicit sn: StoresNumeric[A, T]): T = sn.getNum(value)
  }
}

然后

import StoresNumericSyntax._
implicitly[ANumber[Int] => StoresNumericOps[ANumber[Int]]]

不编译

 Warning:
StoresNumericOps is not a valid implicit value for ANumber[Int] => StoresNumericSyntax.StoresNumericOps[ANumber[Int]] because:
hasMatchingSymbol reported error: type mismatch;
 found   : StoresNumericSyntax.StoresNumericOps.type
 required: ANumber[Int] => StoresNumericSyntax.StoresNumericOps[App393.ANumber[Int]]

同时手动解决

implicitly[ANumber[Int] => StoresNumericOps[ANumber[Int]]](new StoresNumericOps(_)) 

编译和

import StoresNumericSyntax._
a: StoresNumericOps[ANumber[Int]]

也编译。

但是如果我删除 extends AnyVal

object StoresNumericSyntax {
  implicit class StoresNumericOps[A](private val value: A) /*extends AnyVal*/ {
    def getNum[T: Numeric](implicit sn: StoresNumeric[A, T]): T = sn.getNum(value)
  }
}

然后

import StoresNumericSyntax._
implicitly[ANumber[Int] => StoresNumericOps[ANumber[Int]]]

编译。

此外,如果我将隐式 class 拆分为 class + 隐式转换

object StoresNumericSyntax {
  /*implicit*/ class StoresNumericOps[A](private val value: A) extends AnyVal {
    def getNum[T: Numeric](implicit sn: StoresNumeric[A, T]): T = sn.getNum(value)
  }

  implicit def toStoresNumericOps[A](value: A): StoresNumericOps[A] =
    new StoresNumericOps(value)
}

然后

import StoresNumericSyntax._
implicitly[ANumber[Int] => StoresNumericOps[ANumber[Int]]]

编译。

为什么 implicitly[A => B]val x: B = ??? : A 不一样在这里解释:

When calling a scala function with compile-time macro, how to failover smoothly when it causes compilation errors?

What are the hidden rules regarding the type inference in resolution of implicit conversions?

extends AnyVal 的 presence/absence 对隐式解析的影响可能是一个错误,但隐式实例 (implicitly[A => B]) 和隐式转换 (val x: B = ??? : A) 之间的差异更大或不太有意(使用不同的类型推断策略,解析类型参数)。