在scala 2.13中,如何隐式使用[值单例类型]? [英] In scala 2.13, how to use implicitly[value singleton type]?

查看:129
本文介绍了在scala 2.13中,如何隐式使用[值单例类型]?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下简单代码:

  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?

非常感谢您的帮助.

推荐答案

尽管a完全在范围内并且类型一致,但

无法编译:

fails to compile despite that a is totally in the scope and consistent in type:

类型不一致.

考虑示例

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.

我可以做的最短更改是什么?

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

当然可以.您定义了类型为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中,如何隐式使用[值单例类型]?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆