Scala中`type`和`#`关键字的研究

11

能否有人解释一下scala中的type关键字和#运算符如何工作以及如何使用它?请看以下示例。

//Example1
scala>  type t1 = Option.type
defined type alias t1

//Shouldn't this work since previous example simply works?
scala>  type t2 = String.type
<console>:7: error: type mismatch;
 found   : String.type
 required: AnyRef
       type t2 = String.type
         ^

//lets define custom trait T
scala>  trait T
defined trait T

//... and obtain it's type like in Example1.
//Shouldn't this work since previous Example1 simply works?
scala>  type t3 = T.type
<console>:7: error: not found: value T
       type t3 = T.type
         ^

//Lets define some value of type T
scala>  val v4 = new T{}
v4: T = $anon$1@5c3e8c76

//and obtain it's type (works)
scala>  type t4 = v4.type
defined type alias t4

//this doesn't work
scala>  type t4_1 = (new T{}).type
<console>:1: error: identifier expected but 'new' found.
       type t4_1 = (new T{}).type

//as well as this (doesn't work)
scala>  type t5 = "abc".type
<console>:1: error: identifier expected but string literal found.
       type t5 = "abc".type
         ^

//but this compiles well
scala>  val v6 = "abc"
v6: String = abc

scala>  type t6 = v6.type
defined type alias t6


//lets create some values of created types:
scala>  type t1 = Option.type
defined type alias t1

scala>  val v1_1 = Some(10)
v1_1: Some[Int] = Some(10)

scala>  type t7 = v1_1.type
defined type alias t7

scala>  val v7:t7 = null
v7: t7 = null

scala>  val v7_1:t7 = v1_1
v7_1: t7 = Some(10)

scala>  val v7_2:t7 = Some(10)
<console>:9: error: type mismatch;
 found   : Some[Int]
 required: t7
    (which expands to)  v1_1.type
       val v7_2:t7 = Some(10)
             ^


//next let's try # operator

scala>  class X[A,B](a:A,b:B)
defined class X

//doesn't work
scala>  type xa = X[A,B]#A
<console>:8: error: not found: type A
       type xa = X[A,B]#A
           ^
<console>:8: error: not found: type B
       type xa = X[A,B]#A
             ^

//but such approach works:
scala>  trait X2[C]{
  type A
  type B
  val c:C
}
defined trait X2

scala>  type xa2_1 = X2[String]#A
defined type alias xa2_1

scala>  type xa2_2[M] = X2[M]#A
defined type alias xa2_2

2
https://dev59.com/wWw15IYBdhLWcg3wVaQa#6676210 和 https://dev59.com/Xmgv5IYBdhLWcg3wHdR_ - om-nom-nom
2个回答

14

首先,关于type的问题:

类型声明的右侧必须是具有稳定路径的类型名称。因此,逐个考虑您的示例:

type t1 = Option.type

t1是Option 对象类型的别名,而不是Option类。

type t2 = String.type

这是一个错误,因为没有String对象。这个错误有点奇怪,因为String是Java类,所以按照不同的规则操作(因为Java类从不具备伴侣)。

type t3 = T.type

同上。这次错误更加明显,因为T是Scala类,所以编译器可以明确地说“T不是具有类型的对象名称”。

type t4 = v4.type

这是由val v4命名的对象的单例类型。它并不指代任何T类型的实例,甚至也不指代你的new T{}表达式创建的匿名类的任何实例。它指代的是一种类型,只有v4null可以被允许作为该类型的值,也就是说,它们是该类型唯一允许的值。
type t4_1 = (new T{}).type

这是非法的,因为你要获取类型的东西必须是稳定的标识符(大致上,指其引用对象永远不会改变的标识符 -- 如果标识符的完整路径仅由包、objectval的名称组成,则它是稳定的)。
type t5 = "abc".type

同上。
type t6 = v6.type

v6 是一个稳定的标识符。 t6 是仅由被名称 v6 (和 null) 引用的特定 String 实例所占据的类型。

type v6 = v1_1.type

再次,单例类型。

val v7: t7 = null

null 是类型 t7 的一个有效值。

val v7_1:t7 = v1_1

这个特定的对象也是如此。
val v7_2:t7 = Some(10)

但这是一个不同的对象(即使它与v7相等,它也不等于eq),因此它不是该类型的成员。

现在来谈谈#

class X[A,B](a:A,b:B)

AB 是类型参数。它们不能在类外部被引用。你可以把它们想象成带有 private[this] 可见性的抽象类型别名,但这并不完全准确。

type xa = X[A,B]#A

所以,是的,不可见。
type xa2_1 = X2[String]#A

由于这个A是公共类型别名,因此可以在类外部通过名称引用它。请注意,这种情况相当无用,因为您对这种类型一无所知。如果您的特质X2具有返回类型为A的值的方法,则可以执行类似操作。

val aFromX2: xa2_1 = x2instance.methodThatReturnsAnA

但是如果你没有一个具体的实例,你就不能再进行其他操作了,甚至不能将其传回到X2[String]的实例中,因为没有保证这两个A引用相同的类型! 另一方面,如果你有一个具体的实例,你可以这样做:

def passAroundA(x2instance: X2[String]) {
  type x2a = x2instance.A // note dot, not #
  val a: x2a = x2instance.methodThatReturnsAnA
  x2instance.methodThatTakesAnA(a)
}

在这种情况下,它能够工作是因为即使我们不知道 A 实际上是什么,我们知道这两个方法使用的是相同的类型 -- 无论是在 x2instance 构造时固定的任何内容。

请问您能否再写几句关于如何使用点符号访问类型A的内容呢?type x2a = x2instance.A // 注意是点符号,不是# - pawel.panasewicz

2

关于您的问题,几乎所有内容都在这个非常重要的演讲中得到了解释,其中包括模式匹配等用例。我建议您花时间观看它,并努力思考。直到我看了这个视频之前,与scala类型系统相关的许多东西对我来说实际上都是神秘的。如果我知道这些事情,我可能会节省很多时间来解决类型系统和类型推断的奇怪行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接