zoukankan      html  css  js  c++  java
  • 【Scala笔记——道】Scala Predef

    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 契约式编程

  • 相关阅读:
    【转】提高VR渲染速度的最好方法(经典转载)
    【转】提高VR渲染速度的关键
    【转】怎样提高VR渲染速度
    MySql学习05---数据类型
    MySql学习04----数据库表的基本操作
    MySql学习03----数据库基本操作
    MySql学习02----SQL编程的基本概念
    MySql学习01----数据库简介
    MySql学习路线00
    maven07-----maven中的聚合与继承
  • 原文地址:https://www.cnblogs.com/cunchen/p/9464095.html
Copyright © 2011-2022 走看看