本文介绍了<:<运营商在Scala中工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Scala中,有一个类<:<见证了类型约束.来自Predef.scala:

In Scala there's a class <:< that witnesses a type constraint. From Predef.scala:

  sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
  private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
  implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]

如何使用它的一个例子是TraversableOncetoMap方法:

An example of how it's used is in the toMap method of TraversableOnce:

def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] =

我不了解的是这是如何工作的.我了解A <:< B在语法上等同于类型<:<[A, B].但是我不知道,当且仅当A <: B时,编译器如何才能找到该类型的隐式.我认为$conforms定义中的asInstanceOf调用使这成为可能,但是如何?另外,使用抽象类的单例实例而不是仅使用object是否有意义?

What I don't understand is how this works. I understand that A <:< B is syntactically equivalent to the type <:<[A, B]. But I don't get how the compiler can find an implicit of that type if and only if A <: B. I assume that the asInstanceOf call in the definition of $conforms is making this possible somehow, but how? Also, is it significant that a singleton instance of an abstract class is used, instead of just using an object?

推荐答案

假设我们有以下简单的类型层次结构:

Suppose we've got the following simple type hierarchy:

trait Foo
trait Bar extends Foo

我们可以要求证明Bar扩展了Foo:

We can ask for proof that Bar extends Foo:

val ev = implicitly[Bar <:< Foo]

如果我们使用-Xprint:typer在控制台中运行此命令,则会看到以下内容:

If we run this in a console with -Xprint:typer, we'll see the following:

private[this] val ev: <:<[Bar,Foo] =
  scala.this.Predef.implicitly[<:<[Bar,Foo]](scala.this.Predef.$conforms[Bar]);

因此,编译器选择了$conforms[Bar]作为我们要求的隐式值.当然,该值的类型为Bar <:< Bar,但是由于<:<在其第二个类型参数中是协变的,因此它是Bar <:< Foo的子类型,因此非常适合.

So the compiler has picked $conforms[Bar] as the implicit value we've asked for. Of course this value has type Bar <:< Bar, but because <:< is covariant in its second type parameter, this is a subtype of Bar <:< Foo, so it fits the bill.

(Scala编译器知道如何查找要查找的类型的子类型,这有些神奇,但这是一种相当通用的机制,其行为也并不令人惊讶.)

(There's some magic involved here in the fact that the Scala compiler knows how to find subtypes of the type it's looking for, but it's a fairly generic mechanism and isn't too surprising in its behavior.)

现在假设我们要求提供证明Bar扩展了String的证据:

Now suppose we ask for proof that Bar extends String:

val ev = implicitly[Bar <:< String]

如果打开-Xlog-implicits,则会看到以下内容:

If you turn on -Xlog-implicits, you'll see this:

<console>:9: $conforms is not a valid implicit value for <:<[Bar,String] because:
hasMatchingSymbol reported error: type mismatch;
 found   : <:<[Bar,Bar]
 required: <:<[Bar,String]
       val ev = implicitly[Bar <:< String]
                          ^
<console>:9: error: Cannot prove that Bar <:< String.
       val ev = implicitly[Bar <:< String]
                          ^

编译器会再次尝试,但是由于Bar不是String,因此它不是Bar <:< String的子类型,因此这不是我们所需要的.但是$conforms是编译器可以获取<:<实例的唯一位置(除非我们定义了自己的实例,否则将很危险),因此它相当正确地拒绝编译此废话.

The compiler tries the Bar <:< Bar again, but since Bar isn't a String, this isn't a subtype of Bar <:< String, so it's not what we need. But $conforms is the only place the compiler can get <:< instances (unless we've defined our own, which would be dangerous), so it quite properly refuses to compile this nonsense.

要解决您的第二个问题:<:<[-From, +To]类是必需的,因为我们需要该类型类的类型参数才有用.单例Any <:< Any值也可以定义为对象-使用val和匿名类的决定可以说简单一些,但这是您无需担心的实现细节.

To address your second question: the <:<[-From, +To] class is necessary because we need the type parameters for this type class to be useful. The singleton Any <:< Any value could just as well be defined as an object—the decision to use a val and an anonymous class is arguably a little simpler, but it's an implementation detail that you shouldn't ever need to worry about.

这篇关于&lt;:&lt;运营商在Scala中工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-18 15:03