Scala的Predef介绍

前言

Scala每个程序都会自动import以下3个包,分别是 java.lang._ , scala._ 和 Predef._ 。跟Java程序都会自动import java.lang一样。

Predef是一个单例对象,所以我们import进来之后,可以直接使用Predef中定义的方法。

Predef中定义的方法和属性

常用方法和类

def classOf[T]: Class[T] = null // This is a stub method. The actual implementation is filled in by the compiler.

type String        = java.lang.String  // scala中的String使用jdk中的String
type Class[T]      = java.lang.Class[T] // scala中的Class使用jdk中的Class

type Function[-A, +B] = Function1[A, B] // Function1取别名Function

type Map[A, +B] = immutable.Map[A, B] // Map类型默认使用immutable包下的Map
type Set[A]     = immutable.Set[A] // Set类型默认使用immutable包下的Set
val Map         = immutable.Map // Map对象默认使用immutable包下的Map对象(下面测试用到)
val Set         = immutable.Set // Set对象默认使用immutable包下的Set对象(下面测试用到)

一些测试:

// 默认的Map和Set都是immutable包下的,这里的Set和Map都是在Predef中定义的一个变量。
Map(1 -> 1, 2 -> 2) // scala.collection.immutable.Map[Int,Int] = Map(1 -> 1, 2 -> 2)
Set(1,2,3) // scala.collection.immutable.Set[Int] = Set(1, 2, 3)

打印方法

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: _*))

因此,平时我们使用的println,print,printf这些打印方法都是在Predef中定义的,

一些调试和错误方法

// 过期方法,抛出带有message消息的RuntimeException
@deprecated("Use `sys.error(message)` instead", "2.9.0")
def error(message: String): Nothing = sys.error(message)

// 断言。 参数是一个Boolean类型,失败抛出java.lang.AssertionError异常
@elidable(ASSERTION)
def assert(assertion: Boolean) {
if (!assertion)
  throw new java.lang.AssertionError("assertion failed")
}

// 跟上一个方法类似,多了一个message参数。抛出的异常就打印出这个message参数
@elidable(ASSERTION) @inline
final def assert(assertion: Boolean, message: => Any) {
if (!assertion)
  throw new java.lang.AssertionError("assertion failed: "+ message)
}

// 跟assert类似,唯一的区别是assume支持静态经验(static checker)
@elidable(ASSERTION)
def assume(assumption: Boolean) {
if (!assumption)
  throw new java.lang.AssertionError("assumption failed")
}

// 跟assume一样,多了个message参数
@elidable(ASSERTION) @inline
final def assume(assumption: Boolean, message: => Any) {
if (!assumption)
  throw new java.lang.AssertionError("assumption failed: "+ message)
}

// 跟assert类似,只不过抛出的是IllegalArgumentException异常
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)
}

调试和错误方法测试:

assert(1 == 2) // java.lang.AssertionError: assertion failed
assert(1 == 2, "test") // java.lang.AssertionError: assertion failed: test
assume(1 == 2) // java.lang.AssertionError: assumption failed
assume(1 == 2, "test") // java.lang.AssertionError: assumption failed: test
require(1 == 2) // java.lang.IllegalArgumentException: requirement failed
require(1 == 2, "test") // java.lang.IllegalArgumentException: requirement failed: test

一个特殊的属性

Predef中有个 ??? 属性,抛出一个NotImplementedError:

def ??? : Nothing = throw new NotImplementedError

比如定义一些方法的时候,这个方法还没有实现,这个时候可以使用 ???, 而非TODO:

def todoMethod(x: Int): Int = ???

todoMethod(2) // scala.NotImplementedError: an implementation is missing

Predef还有大量的隐式转换和隐式转换类

再讲Predef中的隐式转换和隐式转换类之前,先介绍一下这2个概念。

隐式转换

隐式转换的意思是一个方法中有一个类型的参数,并返回另外一个类型的返回值。比如一个Double类型的方法返回一个Int类型的返回值。

def double2Int(d: Double) = d.toInt

double2Int(2.4) // 2

val a: Int = 2.3 // 报错

重新定义double2Int,使其支持隐式转换:

implicit def double2Int(d: Double) = d.toInt

val a: Int = 2.3 // a: Int = 2

隐式转换类

当需要给Int类型添加一个 –> 方法的时候,需要使用到隐式转换类。因为隐式转换只支持1个参数,所以只能通过隐式转换类完成。

implicit class RangeMaker(left: Int) {
    def -->(right: Int) = left to right
}

val range = 1 --> 10 // Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

隐式转换类有个弊端,那就是每次都会创建一个类的实例,有时候这完全没有必要。

scala提供了一个将隐式转换类转换成value class的方法,只需要继承AnyVal即可,还需要注意参数需要加上val标识符。

implicit class RangeMaker(val left: Int) extends AnyVal {
    def -->(right: Int) = left to right
}

Predef中的隐式转换和隐式转换类

-> 方法:

implicit final class ArrowAssoc[A](private val self: A) extends AnyVal {
    @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(self, y)
    def →[B](y: B): Tuple2[A, B] = ->(y)
}

生成一个二元元组,Tuple2。

1 → 2  // (Int, Int) = (1, 2)
1 -> 2 // (Int, Int) = (1, 2)

ensuring 方法:

implicit final class Ensuring[A](private val self: A) extends AnyVal {
    def ensuring(cond: Boolean): A = { assert(cond); self }
    def ensuring(cond: Boolean, msg: => Any): A = { assert(cond, msg); self }
    def ensuring(cond: A => Boolean): A = { assert(cond(self)); self }
    def ensuring(cond: A => Boolean, msg: => Any): A = { assert(cond(self), msg); self }
}

ensuring内部调用assert方法。

def doublePositive(n: Int): Int = {
    n * 2
} ensuring(n => n >= 0 && n % 2 == 0)

doublelPositive(1) // 2
doublelPositive(-1) // java.lang.AssertionError: assertion failed

formatted 方法:

implicit final class StringFormat[A](private val self: A) extends AnyVal {
    @inline def formatted(fmtstr: String): String = fmtstr format self
}

格式化字符串,使用java.lang.String.format方法。

"Format" formatted "%s, let's go" // Format, let's go

+ 方法:

implicit final class any2stringadd[A](private val self: A) extends AnyVal {
    def +(other: String): String = String.valueOf(self) + other
}

case class使用+方法:

case class Student(name: String, age: Int)
Student("format", 11) + " 22" // Student(format,11) 22

StringOps类:

@inline implicit def augmentString(x: String): StringOps = new StringOps(x)
@inline implicit def unaugmentString(x: StringOps): String = x.repr

StringOps提供了丰富的原生String没提供的方法:

"format".length // 6 原生String是没有提供length方法的
"format".foreach(println(_))
"format".stripPrefix("for") // mat
"format".slice(1, 3) // or
"format" * 5 // formatformatformatformatformat
"true".toBoolean // true

ArrayOps类:

implicit def genericArrayOps[T](xs: Array[T]): ArrayOps[T] = (xs match {
    case x: Array[AnyRef]  => refArrayOps[AnyRef](x)
    case x: Array[Boolean] => booleanArrayOps(x)
    case x: Array[Byte]    => byteArrayOps(x)
    case x: Array[Char]    => charArrayOps(x)
    case x: Array[Double]  => doubleArrayOps(x)
    case x: Array[Float]   => floatArrayOps(x)
    case x: Array[Int]     => intArrayOps(x)
    case x: Array[Long]    => longArrayOps(x)
    case x: Array[Short]   => shortArrayOps(x)
    case x: Array[Unit]    => unitArrayOps(x)
    case null              => null
}).asInstanceOf[ArrayOps[T]]


  implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps.ofBoolean(xs)
  implicit def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte]          = new ArrayOps.ofByte(xs)
  implicit def charArrayOps(xs: Array[Char]): ArrayOps[Char]          = new ArrayOps.ofChar(xs)
  implicit def doubleArrayOps(xs: Array[Double]): ArrayOps[Double]    = new ArrayOps.ofDouble(xs)
  implicit def floatArrayOps(xs: Array[Float]): ArrayOps[Float]       = new ArrayOps.ofFloat(xs)
  implicit def intArrayOps(xs: Array[Int]): ArrayOps[Int]             = new ArrayOps.ofInt(xs)
  implicit def longArrayOps(xs: Array[Long]): ArrayOps[Long]          = new ArrayOps.ofLong(xs)
  implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T]    = new ArrayOps.ofRef[T](xs)
  implicit def shortArrayOps(xs: Array[Short]): ArrayOps[Short]       = new ArrayOps.ofShort(xs)
  implicit def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit]          = new ArrayOps.ofUnit(xs)

ArrayOps提供了丰富的原生数组没提供的方法:

Array(1, 2, 3) :+ 4 // Array(1, 2, 3, 4)

Scala程序员可以较少关心装箱和拆箱操作,这也是由于Predef对象里定义了Scala值类型与java基本类型直接的隐式转换:

implicit def byte2Byte(x: Byte)           = java.lang.Byte.valueOf(x)
implicit def short2Short(x: Short)        = java.lang.Short.valueOf(x)
implicit def char2Character(x: Char)      = java.lang.Character.valueOf(x)
implicit def int2Integer(x: Int)          = java.lang.Integer.valueOf(x)
implicit def long2Long(x: Long)           = java.lang.Long.valueOf(x)
implicit def float2Float(x: Float)        = java.lang.Float.valueOf(x)
implicit def double2Double(x: Double)     = java.lang.Double.valueOf(x)
implicit def boolean2Boolean(x: Boolean)  = java.lang.Boolean.valueOf(x)

implicit def Byte2byte(x: java.lang.Byte): Byte             = x.byteValue
implicit def Short2short(x: java.lang.Short): Short         = x.shortValue
implicit def Character2char(x: java.lang.Character): Char   = x.charValue
implicit def Integer2int(x: java.lang.Integer): Int         = x.intValue
implicit def Long2long(x: java.lang.Long): Long             = x.longValue
implicit def Float2float(x: java.lang.Float): Float         = x.floatValue
implicit def Double2double(x: java.lang.Double): Double     = x.doubleValue
implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
本文作者:Format
原文链接: http://fangjian0423.github.io/2015/10/07/scala-predef/
版权归作者所有,转载请注明出处