隐式视图不起作用 - 我的隐式定义应该受到指责吗?
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]
并不总是检查是否存在从 A
到 B
的隐式转换。 *
(见下文)
其次(#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
) 之间的差异更大或不太有意(使用不同的类型推断策略,解析类型参数)。
我在使用隐式视图时遇到了一些问题。我怀疑这是非常微不足道的,并且可能有一些简单得令人尴尬的答案。我有这样的情况,以及(显然,不成功)调试它的尝试:
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]
并不总是检查是否存在从 A
到 B
的隐式转换。 *
(见下文)
其次(#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
) 之间的差异更大或不太有意(使用不同的类型推断策略,解析类型参数)。