Scala Predef
好奇的开始
最近碰到了一段代码,执行结果与想的不同,因此想通过反编译看一下究竟是如何运行的
scala编译和java的编译很类似,java中我们使用javac编译,scala中使用scalac编译。
编译 生成对应的 class 文件,直接可以使用 javap 反编译
反编译结果如下
public final class Test$ {
...
public void main(java.lang.String[]);
Code:
0: getstatic #25 // Field scala/collection/immutable/List$.MODULE$:Lscala/collection/immutable/List$;
3: getstatic #30 // Field scala/Predef$.MODULE$:Lscala/Predef$;
6: iconst_2
在实例化List时,发现会引入一个静态静态类——Predef,很好奇这个类是干什么的,于是有了今天这帖子。
隐式引入Predef
Scala会在编译期自动给一个对象添加隐式依赖,就像Java程序会自动加上java.lang包一样。Scala中,以下三个包的内容会隐式引用到每个程序上。所不同的是,Scala还会隐式加进对Predef的引用,这极大方便了程序员的工作。
import java.lang._ // in JVM projects, or system namespace in .NET
import scala._ // everything in the scala package
import Predef._ // everything in the Predef object
上面三个包,包含了常用的类型和方法。java.lang包包含了常用的java语言类型,如果在.NET环境中,则会引用system命名空间。类似的,scala还会隐式引用scala包,也就是引入常用的scala类型。
上述三个语句的顺序藏着一点玄机。我们知道,通常,如果import进来两个包都有某个类型的定义的话,比如说,同一段程序,即引用了’scala.collection.mutable.Set’又引用了’import scala.collection.immutable.Set’则编译器会提示无法确定用哪一个Set。这里的隐式引用则不同,如果有相同的类型,后面的包的类型会将前一个隐藏掉。比如,java.lang和scala两个包里都有StringBuilder,这种情况下,会使用scala包里定义的那个。java.lang里的定义就被隐藏掉了,除非显示的使用java.lang.StringBuilder。
Predef作用
Predef 主要帮助我们做了三件事
- 自动引入常用类型
- Console.print 简化
- 断言支持
- 隐式类型转化
自动引入常用类型
Prodef 会自动引入常用的类型,例如Scala基本数据类型、 scala.collection.immutable.Map
、scala.collection.immutable.List
、scala.collection.immutable.::
以及scala.collection.immutable.Nil
等常用类型。
Predef是通过如下代码实现常用基本数据类型的引入
object Predef extends LowPriorityImplicits with DeprecatedPredef {
...
scala.`package` //强制scala.package 中类型可见
// 别名 以及简化引入
type Map[A, +B] = immutable.Map[A, B]
type Set[A] = immutable.Set[A]
val Map = immutable.Map
val Set = immutable.Set
实际在scala.package源码中,引入了
- 异常结构 Throable、Exception、 Error
- 常用异常类型 RuntimeExc eption、 NullPointerException 、 IndexOutOfBoundsException、 ArrayIndexOutOfBoundsException、 StringIndexOutOfBoundException、 UnsupportedOperationException、 NoSuchElementException、 NumberFormateException、 AbstractMethodEerror、 InterruptedException
- AnyRef 类型
- 遍历相关接口 Ierable、 IndexSeq、 Iterator
- ADT 类型 Seq 、 List、 Nil、 Stream、 Vector、 StringBuilder、 Either、 Left、 Right
- ADT操作 :: 、 +: 、 :+、 #::
- Range接口
- 基本数据类型 BigDecimal、 BigInt、Integral、 Numeric、
- 计算工具 Equiv、Ordered、 Odering、 PartialOrdering、 PartiallyOrdered
再加上在Predef中帮我们引入了两种ADT类型
- Map
- Set
实际上在代码中,不需要去额外引入其他List或者Map ,直接就可以实现,并且对于ADT 的一些操作 :: 、 :+ 都是Prodef帮助我们完成的
具体源码可以参照 scala.scala
Console 引入
实际上,在使用 print
和 println
时 ,实际调用的是scala.Console.print
和scala.Console.println
。而这部分工作也是Predef替我们去做的,具体实现如下
def print(x: Any) = Console.print(x)
def println() = Console.println()
def println(x: Any) = Console.println(x)
def printf(text: String, xs: Any*) = Console.print(text.format(xs: _*))
断言支持
断言支持 assume
, require
and ensuring
引申 契约式编程
具体实现如下
@elidable(ASSERTION)
def assume(assumption: Boolean) {
if (!assumption)
throw new java.lang.AssertionError("assumption failed")
}
@elidable(ASSERTION) @inline
final def assume(assumption: Boolean, message: => Any) {
if (!assumption)
throw new java.lang.AssertionError("assumption failed: "+ message)
}
def require(requirement: Boolean) {
if (!requirement)
throw new IllegalArgumentException("requirement failed")
}
@inline final def require(requirement: Boolean, message: => Any) {
if (!requirement)
throw new IllegalArgumentException("requirement failed: "+ message)
}
类型转换
隐式类型转换主要是通过继承 scala.LowPriorityImplicits实现,提供了常用的各种基本类型的转换以及一些常用 基本类型的ADT 类型的转化
在Predef中 也提供了一些 基本类型的互相转化以及一些 ADT 类型的想换转化,JAVA中有自动拆箱装箱,scala中虽然基本类型皆对象化处理,但底层也是通过 也是包含的 自动 拆箱装箱。
Predef 同样提供了这部分的实现。
Java基本类型与Scala基本类型转化
implicit def byte2Byte(x: Byte): java.lang.Byte = x.asInstanceOf[java.lang.Byte]
implicit def short2Short(x: Short): java.lang.Short = x.asInstanceOf[java.lang.Short]
implicit def char2Character(x: Char): java.lang.Character = x.asInstanceOf[java.lang.Character]
implicit def int2Integer(x: Int): java.lang.Integer = x.asInstanceOf[java.lang.Integer]
implicit def long2Long(x: Long): java.lang.Long = x.asInstanceOf[java.lang.Long]
implicit def float2Float(x: Float): java.lang.Float = x.asInstanceOf[java.lang.Float]
implicit def double2Double(x: Double): java.lang.Double = x.asInstanceOf[java.lang.Double]
implicit def boolean2Boolean(x: Boolean): java.lang.Boolean = x.asInstanceOf[java.lang.Boolean]
implicit def Byte2byte(x: java.lang.Byte): Byte = x.asInstanceOf[Byte]
implicit def Short2short(x: java.lang.Short): Short = x.asInstanceOf[Short]
implicit def Character2char(x: java.lang.Character): Char = x.asInstanceOf[Char]
implicit def Integer2int(x: java.lang.Integer): Int = x.asInstanceOf[Int]
implicit def Long2long(x: java.lang.Long): Long = x.asInstanceOf[Long]
implicit def Float2float(x: java.lang.Float): Float = x.asInstanceOf[Float]
implicit def Double2double(x: java.lang.Double): Double = x.asInstanceOf[Double]
implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.asInstanceOf[Boolean]
参考