在 scala 2.13 中,如何使用隐式[值单例类型]?



以下简单代码:

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讨论后,我想我明白了你的意思。所以我们应该说编译器不喜欢召唤单例。

相关内容

  • 没有找到相关文章

最新更新