隐式视图不起作用-我的隐式定义应归咎于我吗? [英] Implicit view not working - is my implicit def to blame?

查看:80
本文介绍了隐式视图不起作用-我的隐式定义应归咎于我吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用隐式视图时遇到了一些麻烦.我怀疑这很琐碎,可能会有一些令人尴尬的简单答案.我遇到这样的情况,以及(显然是不成功的)尝试对其进行调试:

I'm having some trouble with an implicit view. I suspect this is quite trivial and may have some embarassingly easy answer. I have a situation like this, along with (obviously, unsuccessful) attempts to debug it:

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的缺乏理解实际上是可以解决的.我不确定泛型扮演什么角色-应该使用第一个泛型参数来表示我实际上想要转换的类型,还是可以吗?

I think the issue here is my implicit def, or more accurately my lack of understanding about implicit def is actually meant to work. I'm not sure what role the generics play - should the first generic argument be used to represent the type I would actually like converted, or is it OK as it is?

非常感谢收到任何帮助.

Any help gratefully received.

推荐答案

首先(#3)

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

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

is wrong. You do not define an implicit conversion from a data type to a type class, you define an implicit conversion from a data type to an implicit class introducing extension method. So it should be

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

它会编译.

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

Be prepared that implicitly[A => B] not always checks that an implicit conversion from A to B exists. * (see below)

第二(#4),当您使用扩展方法(a.getNum)时,应导入语法对象:

Secondly (#4), when you use extension method (a.getNum) you should import syntax object:

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之一.试试

If you import IntIsIntegral you'll add this implicit to the local scope (before that it was in the implicit scope only), so you'll make its "priority" "higher" than the one of BigIntIsIntegral. Try

import StoresNumericSyntax._
import Numeric.IntIsIntegral
a.getNum

它会编译.

Scala 2.13.3.

Scala 2.13.3.

另请参阅如何在编译时调试隐式:

See also how to debug implicits (at compile time): In scala 2 or 3, is it possible to debug implicit resolution process in runtime?

*例如,如果您将隐式类修改为注释中建议的 @LuisMiguelMejíaSuárez

* For example if you modify the implicit class as @LuisMiguelMejíaSuárez advised in comments

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]]]

编译.

另外,如果我将隐式类拆分为一个类+隐式转换

Also if I split the implicit class into a class + an implicit conversion

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不同的原因在这里说明:

Why implicitly[A => B] is not the same as val x: B = ??? : A is expained here:

在scala,在任何情况下隐式视图都无法传播到其他隐式函数吗?

调用具有编译时宏的scala函数,当导致编译错误时如何顺利进行故障转移?

Scala Kleisli在IntelliJ中抛出错误

什么是有关隐式转换解析中类型推断的隐藏规则?

Scala:`模糊隐式值`,但找不到正确的值

extends AnyVal存在/不存在对隐式解析的影响可能是一个错误,但是隐式实例(implicitly[A => B])与隐式转换(val x: B = ??? : A)之间的区别或多或少是有意的(不同类型的推断策略,使用解析类型参数).

The impact of presence/absence of extends AnyVal on implicit resolution can be a bug but difference between implicit instance (implicitly[A => B]) and implicit conversion (val x: B = ??? : A) is more or less intentional (different strategies of type inference, resolving type parameters are used).

这篇关于隐式视图不起作用-我的隐式定义应归咎于我吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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