【Scala笔记——道】Scala Predef

版权声明:转载请注明出处,欢迎各位斧正 https://blog.csdn.net/wang135139/article/details/79658250

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.Mapscala.collection.immutable.Listscala.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 引入

实际上,在使用 printprintln 时 ,实际调用的是scala.Console.printscala.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]

参考

Scala的Predef对象

WIKI 契约式编程

猜你喜欢

转载自blog.csdn.net/wang135139/article/details/79658250