以下简单代码:
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:我刚刚意识到注释"字符串"是罪魁祸首,以下代码总数有效:
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]()
是没有意义的,因为它的行为应该像标准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讨论后,我想我明白了你的意思。所以我们应该说编译器不喜欢召唤单例。