scala - 在 scala 2.13 中,如何隐式使用[value singleton type]?
问题描述
以下简单代码:
implicit val a: String = "abc"
implicitly[a.type]
尽管a
完全在范围内并且类型一致,但仍无法编译:
Error:(9, 13) could not find implicit value for parameter e:
...AP.a.type with Singleton
implicitly[a.type with Singleton]
这种不一致的行为似乎是故意的。这个设计的意义何在?我能做的最短的改变是什么让它编译?
更新1:我刚刚意识到注释“String”是罪魁祸首,以下代码总有效:
val a: String = "abc"
implicit val aa: a.type = a
implicitly[a.type]
不幸的是它包含很多重复的定义,有没有机会让它更短?
非常感谢你的帮助。
解决方案
尽管
a
完全在范围内并且类型一致,但仍无法编译:
它的类型不一致。
考虑例子
trait Parent
trait Child extends Parent
{
implicit val p: Parent = null
// implicitly[Child] // doesn't compile
}
{
implicit val c: Child = null
implicitly[Parent] // compiles
}
同样,在我们的案例a.type <: String
中,您声明了类型的隐式String
,因此a.type
找不到类型的隐式。
如果您有某种类型的隐式,它也适用于所有超类型,但不适用于所有子类型(严格)。这只是里氏原理。这就是为什么你不应该寻找类型的隐式Any
或定义类型的隐式Nothing
。
类似地,如果一个类型类是协变的,那么这个类型类的一个实例的所有超类型也是它的实例
trait TC[+A]
{
implicit val inst: TC[Parent] = null
// implicitly[TC[Child]] // doesn't compile
}
{
implicit val inst: TC[Child] = null
implicitly[TC[Parent]] // compiles
}
如果一个类型类是逆变的,那么这个类型类的一个实例的所有子类型也是它的实例
trait TC1[-A]
{
implicit val inst: TC1[Parent] = null
implicitly[TC1[Child]] // compiles
}
{
implicit val inst: TC1[Child] = null
// implicitly[TC1[Parent]] // doesn't compile
}
显然,对于不变类型类没有这样的属性。
我能做的最短的改变是什么让它编译?
它不应该编译。
更新1:我刚刚意识到注释“字符串”是罪魁祸首,以下代码总有效
确实如此。您定义了类型a.type
的隐式,因此找到了这种类型a.type
的隐式。
如果您正在寻找超类型的隐含,您可以这样做
def implicitSupertypeOf[A] = new PartiallyAppliedImplicitSupertypeOf[A]
class PartiallyAppliedImplicitSupertypeOf[A] {
def apply[B]()(implicit b: B, ev: A <:< B): B = b
// by the way, the following will not work:
// def apply[B]()(implicit ev: A <:< B, b: B): B = b
// def apply[B >: A]()(implicit b: B): B = b
}
import Predef.{$conforms => _, _}
{
implicit val p: Parent = null
implicitSupertypeOf[Child]() //compiles
}
{
implicit val inst: TC[Parent] = null
implicitSupertypeOf[TC[Child]]() //compiles
}
{
implicit val inst: TC1[Child] = null
implicitSupertypeOf[TC1[Parent]]() //compiles
}
{
implicit val a: String = "abc"
implicitSupertypeOf[a.type]() //compiles
implicitSupertypeOf["abc"]() //compiles
}
从上面可以看出,定义没有意义,implicitSubtypeOf[A]()
因为它的行为应该像 standard implicitly[A]
。
顺便说一句,我们还可以修改 的行为,implicitly
以便它只接受没有子类型的确切类型
def implicitExactTypeOf[A] = new PartiallyAppliedImplicitExactTypeOf[A]
class PartiallyAppliedImplicitExactTypeOf[A] {
def apply[B <: A]()(implicit b: B, ev: A =:= B) = b
}
{
implicit val p: Parent = null
// implicitExactTypeOf[Child]() // doesn't compile
implicitExactTypeOf[Parent]() // compiles
}
{
implicit val c: Child = null
implicitExactTypeOf[Child]() // compiles
// implicitExactTypeOf[Parent]() // doesn't compile
}
{
implicit val inst: TC[Parent] = null
// implicitExactTypeOf[TC[Child]]() // doesn't compile
implicitExactTypeOf[TC[Parent]]() //compiles
}
{
implicit val inst: TC1[Child] = null
implicitExactTypeOf[TC1[Child]]() //compiles
// implicitExactTypeOf[TC1[Parent]]() // doesn't compile
}
{
implicit val a: String = "abc"
implicitExactTypeOf[String]() // compiles
// implicitExactTypeOf["abc"]() // doesn't compile
// implicitExactTypeOf[a.type]() // doesn't compile
}
我们也可以实现implicitStrictSupertypeOf
(接受超类型但不接受类型本身),implicitStrictSubtypeOf
(如implicitly
接受子类型但不接受类型本身)。
实际上,在与@HTNW讨论之后,我想我理解了你的观点。所以我们应该说编译器不喜欢召唤单例。
推荐阅读
- python - 无法将 django 对象传递给 Angular 前端
- agens-graph - 如何提高 AgensGraph 上最短路径的性能?
- php - 下载开始包含在报价中
- c++ - 使用循环创建条形图
- android - Android 闹钟被其他应用取消
- c++ - 奇数/偶数总数
- javascript - Node.js:暂停执行并运行异步清理代码
- java - 如何在最终的 TreeSet 中创建硬编码的不区分大小写的值,以便只有“香蕉”而不是“香蕉”作为另一个值
- python - 等效字符串在 Python 中不给出等效的位串
- ruby-on-rails - Bootstrap javascript 需要重新加载,或无法正常工作