问题描述
以下简单代码:
implicit val a: String = "abc"
implicitly[a.type]
尽管a
完全在范围内并且类型一致,但
无法编译:
fails to compile despite that a
is totally in the scope and consistent in type:
Error:(9, 13) could not find implicit value for parameter e:
...AP.a.type with Singleton
implicitly[a.type with Singleton]
看来这种不一致的行为是故意的.这种设计的重点是什么?我可以做的最短的更改是什么?
It appears that this inconsistent behaviour is deliberate. What's the point of this design? What is the shortest change I can do to make it compile?
更新1 :我刚刚意识到注释"String"已包含是罪魁祸首,以下代码合计工作:
UPDATE 1: I just realised that the annotation "String" is the culprit, the following code total worked:
val a: String = "abc"
implicit val aa: a.type = a
implicitly[a.type]
不幸的是,它包含很多重复的定义,是否有机会使其更短?
Unfortunately it contains a lot of duplicated definition, is there any chance to make it shorter?
非常感谢您的帮助.
推荐答案
考虑示例
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
的隐式.
Similarly in our case a.type <: String
, you declared implicit of type String
, so implicit of type a.type
is not found.
如果您具有某种类型的隐式对象,则它也将对所有超类型均有效,但不适用于所有子类型(严格而言).这只是 Liskov原则.这就是为什么您不应该寻找类型为Any
的隐式或定义类型为Nothing
的隐式.
If you have an implicit of some type it will work also for all supertypes but will not work for all subtypes (strictly). This is just Liskov principle. That's why you shouldn't look for implicit of type Any
or define implicit of type Nothing
.
类似地,如果类型类是协变的,则该类型类的实例的所有超类型也都是其实例
Similarly, if a type class is covariant then all supertypes of an instance of this type class are also its instances
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
}
如果类型类是逆变的,则该类型类的实例的所有子类型也都是其实例
If a type class is contravariant then all subtypes of an instance of this type class are also its instances
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
}
很明显,对于不变类型类,没有这样的属性.
Clearly, for invariant type classes there is no such property.
当然可以.您定义了类型为a.type
的隐式,因此可以找到类型为a.type
的隐式.
Surely it does. You defined implicit of type a.type
so implicit of this type a.type
is found.
如果您正在寻找超类型的隐式,可以这样做
If you are looking for implicits of supertypes you can do
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]
相同.
From the above it follows that there is no sense to define implicitSubtypeOf[A]()
because it should behave just like standard implicitly[A]
.
顺便说一句,我们还可以修改implicitly
的行为,使其只接受不带子类型的精确类型
By the way, we can also modify behavior of implicitly
so that it will accept only exact type without subtypes
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
接受子类型,但不接受类型本身).
Also we can implement implicitStrictSupertypeOf
(accepting supertypes but not the type itself), implicitStrictSubtypeOf
(like implicitly
accepting subtypes but it will not accept the type itself).
实际上,在与 @HTNW 讨论之后,我想我理解了你的意思.因此,我们应该说编译器不喜欢召唤单例.
Actually after discussion with @HTNW I guess I understood your point. So we just should say that compiler doesn't like to summon singletons.
这篇关于在scala 2.13中,如何隐式使用[值单例类型]?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!