Scala编译器特别支持哪些类型?

55

Scala非常强调看似是语言特性其实是库特性的实现。

那么有没有一份列出了语言中被特殊对待的类型的清单呢?

无论是在规范中还是作为实现细节?

这将包括例如优化元组匹配的内容。

关于模式匹配、for推导、try-catch块和其他语言结构的特殊约定是什么?

编译器是否会特别处理字符串?我看到字符串增强只是一个库内隐式转换,字符串连接由 Predef 支持,但它是否被语言特别处理?

同样地,我看到关于<: <classOfasInstanceOf的问题,不清楚哪些是神奇的内部机制。是否有一种方法可以通过编译器选项或查看字节码来区分它们的差异?

我想了解一个功能是否被Scala.JS和Scala-native等实现统一支持,还是说这个功能可能实际上取决于库实现,因此具有实现依赖性。


离一个正确的答案还有很远的距离,但这可能会有所帮助,以澄清一点:http://docs.scala-lang.org/tutorials/tour/unified-types.html - Moritz
1个回答

81

编译器已知有大量类型,它们的特殊性各不相同。您可以在scalac的Definitions.scala中找到完整列表。

我们可以根据它们的特殊程度进行分类。

免责声明: 我可能忘记了一些。

对类型系统特别重要

以下类型对Scala的类型系统至关重要。它们对类型检查本身的执行方式产生影响。所有这些类型都在规范中提到(或者,它们绝对应该被提到)。

  • AnyAnyRefAnyValNullNothing:这五种类型位于Scala类型系统的顶部和底部。
  • scala.FunctionN,匿名函数(包括函数的 eta 扩展)的规范类型。即使在具有 SAM 对待匿名函数的 2.12 版本中,在某些情况下(尤其是在重载解析中),FunctionN仍然是特殊的。
  • scala.PartialFunction(对类型推断有影响)
  • Unit
  • 带有文本表示法的所有类型:IntLongFloatDoubleCharBooleanStringSymboljava.lang.Class
  • 所有数字原始类型和Char,用于弱一致性(这两个项目涵盖了所有原始类型)
  • Option 和元组(用于模式匹配和自动元组展开)
  • java.lang.Throwable
  • scala.Dynamic
  • scala.Singleton
  • 大多数 scala.reflect.*,特别是 ClassTagTypeTag 等等。
  • scala.annotation.{,ClassFile,Static}Annotation
  • 几乎所有在 scala.annotation.* 中的注释(例如,unchecked
  • scala.language.*
  • scala.math.ScalaNumber(出于晦涩的原因)

作为某些语言特性展开的已知类型

以下类型对类型系统并不重要。它们对类型检查没有影响。然而,Scala语言确实包含一些将展开为这些类型的表达式的构造。

这些类型也会在规范中提到。

  • scala.collection.SeqNilWrappedArray,用于可变参数。
  • TupleN类型
  • ProductSerializable(用于case类)
  • 由模式匹配构造生成的MatchError
  • scala.xml.*
  • scala.DelayedInit
  • List(编译器在这些上执行一些微不足道的优化,如将List()重写为Nil

对语言实现已知

这可能是您最关心的列表,因为您说您有兴趣了解不同后端可以有何不同。前面的分类由编译器的早期(前端)阶段处理,因此Scala/JVM、Scala.js和Scala Native都共享这些。这个类别通常被编译器后端知道,所以可能会有不同的处理方式。请注意,Scala.js和Scala Native都尽力模拟Scala/JVM的语义。

这些类型可能不会在语言规范中明确提到,至少不是所有的类型。

以下是后端达成一致的地方(就我所知,针对Scala Native):

  • 所有基本类型:BooleanCharByteShortIntLongFloatDoubleUnit
  • scala.Array
  • Cloneable(目前在Scala Native中不受支持,参见#334
  • StringStringBuilder(主要用于字符串连接)
  • Object,几乎所有的方法都适用

以下是他们意见不一致的地方:

  • 基本类型的装箱版本(如java.lang.Integer
  • Serializable
  • java.rmi.Remotejava.rmi.RemoteException
  • scala.annotation.*中的某些注释(例如strictfp
  • java.lang.reflect.*中的一些东西,Scala/JVM用它来实现结构类型
此外,虽然它们本质上不是“类型”,但是后端也会专门处理大量原始方法

特定于平台的类型

除了上面提到的所有平台都可用的类型之外,非JVM平台还会添加自己特定的类型以实现互操作性。

Scala.js特殊类型

请参见JSDefinitions.scala

  • js.Any:在概念上除了AnyValAnyRef之外的第三个子类型。它们具有JavaScript语义而不是Scala语义。
  • String和所有基本类型的装箱版本(被编译器大幅重写,所谓的“劫持”)
  • js.ThisFunctionN:它们的apply方法与其他JavaScript类型的行为不同(第一个实际参数成为调用函数的thisArgument
  • js.UndefOrjs.|(即使它们不扩展js.Any,它们也会像JS类型一样运行)
  • js.Objectnew js.Object()特殊处理为一个空的JS对象文字{}
  • js.JavaScriptException (在throwcatch中表现非常特别)
  • js.WrappedArray(被展开成可变参数的语法糖)
  • js.ConstructorTag(类似于ClassTag
  • 注释js.native,以及js.annotation.*中的所有注释

此外还有一打原始方法

Scala Native特殊类型

请参见NirDefinitions.scala

  • 无符号整数: UByteUShortUIntULong
  • Ptr,指针类型
  • FunctionPtrN,函数指针类型
  • native.* 中的注释
  • scala.scalanative.runtime 中的一些额外原始方法

2
感谢您慷慨的回答。稍后,我可能会添加一个关于Privileged by virtue of Predef的部分。 - som-snytt
@som-snytt 我还添加了一些特定于平台的特殊类型列表。 - sjrd
请问您能详细说明一下“SAM处理匿名函数”是什么吗?SAM处理是什么? - Kevin Meredith
1
SAM处理是将FunctionN视为常规的Single Abstract Method trait,类似于其他如Runnable。您可以在2.12中使用匿名函数代替SAM类型的值,因此FunctionN已经失去了其作为匿名函数唯一类型的“特殊地位”。 - sjrd
4
OptionTupleN 不再是模式匹配中的特殊情况。现在,模式匹配是结构化的,并接受任何 { def isEmpty: Boolean; def get: T },其中 T 如果有名为 _1 等的成员,则被视为元组,否则被视为一个值。 - HTNW

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