Scala Predef物件詳解
Scala Predef物件
目錄:
1.Predef原始碼
2.型別裝換
3.型別定義
4.條件檢查方法
5.輸入輸出方法
6.其他
1 Predef原始碼
為了方便起見,只要你編譯程式碼,Scala 編譯器就會自動匯入頂層Scala 包(名為scala)以及在java.lang 包(就像javac 的)中的定義。因此,許多常見的Java 和Scala 型別都可以不經過明顯地匯入或提供完整的名稱就可以使用。另外,編譯器還匯入了Predef 物件中的一些定。接下來,我們來詳細瞭解Predef 提供的特性。需要注意的是,Scala 2.11 版本的Predef 引入了很多變化,其中大部分是不可見的。
看一看原始碼:
package scala object Predef extends scala.LowPriorityImplicits with scala.DeprecatedPredef { def classOf[T] : Predef.Class[T] = { /* compiled code */ } type Class[T] = java.lang.Class[T] type String = java.lang.String type Function[-A, +B] = scala.Function1[A, B] type Map[A, +B] = scala.collection.immutable.Map[A, B] type Set[A] = scala.collection.immutable.Set[A] val Map : scala.collection.immutable.Map.type = { /* compiled code */ } val Set : scala.collection.immutable.Set.type = { /* compiled code */ } @scala.deprecated("use `scala.reflect.ClassTag` instead", "2.10.0") @scala.annotation.implicitNotFound("No ClassManifest available for ${T}.") type ClassManifest[T] = scala.reflect.ClassManifest[T] type OptManifest[T] = scala.reflect.OptManifest[T] @scala.annotation.implicitNotFound("No Manifest available for ${T}.") type Manifest[T] = scala.reflect.Manifest[T] @scala.deprecated("use `scala.reflect.ClassTag` instead", "2.10.0") val ClassManifest : scala.reflect.ClassManifestFactory.type = { /* compiled code */ } val Manifest : scala.reflect.ManifestFactory.type = { /* compiled code */ } val NoManifest : scala.reflect.NoManifest.type = { /* compiled code */ } def manifest[T](implicit m : Predef.Manifest[T]) : Predef.Manifest[T] = { /* compiled code */ } @scala.deprecated("use scala.reflect.classTag[T] instead", "2.10.0") def classManifest[T](implicit m : Predef.ClassManifest[T]) : Predef.ClassManifest[T] = { /* compiled code */ } def optManifest[T](implicit m : Predef.OptManifest[T]) : Predef.OptManifest[T] = { /* compiled code */ } @scala.inline def identity[A](x : A) : A = { /* compiled code */ } @scala.inline def implicitly[T](implicit e : T) : T = { /* compiled code */ } @scala.inline def locally[T](x : T) : T = { /* compiled code */ } @scala.annotation.elidable(2000) def assert(assertion : scala.Boolean) : scala.Unit = { /* compiled code */ } @scala.inline @scala.annotation.elidable(2000) final def assert(assertion : scala.Boolean, message : => scala.Any) : scala.Unit = { /* compiled code */ } @scala.annotation.elidable(2000) def assume(assumption : scala.Boolean) : scala.Unit = { /* compiled code */ } @scala.inline @scala.annotation.elidable(2000) final def assume(assumption : scala.Boolean, message : => scala.Any) : scala.Unit = { /* compiled code */ } def require(requirement : scala.Boolean) : scala.Unit = { /* compiled code */ } @scala.inline final def require(requirement : scala.Boolean, message : => scala.Any) : scala.Unit = { /* compiled code */ } def ??? : scala.Nothing = { /* compiled code */ } @scala.deprecated("use built-in tuple syntax or Tuple2 instead", "2.11.0") type Pair[+A, +B] = scala.Tuple2[A, B] @scala.deprecated("use built-in tuple syntax or Tuple2 instead", "2.11.0") object Pair extends scala.AnyRef { def apply[A, B](x : A, y : B) : scala.Tuple2[A, B] = { /* compiled code */ } def unapply[A, B](x : scala.Tuple2[A, B]) : scala.Option[scala.Tuple2[A, B]] = { /* compiled code */ } } @scala.deprecated("use built-in tuple syntax or Tuple3 instead", "2.11.0") type Triple[+A, +B, +C] = scala.Tuple3[A, B, C] @scala.deprecated("use built-in tuple syntax or Tuple3 instead", "2.11.0") object Triple extends scala.AnyRef { def apply[A, B, C](x : A, y : B, z : C) : scala.Tuple3[A, B, C] = { /* compiled code */ } def unapply[A, B, C](x : scala.Tuple3[A, B, C]) : scala.Option[scala.Tuple3[A, B, C]] = { /* compiled code */ } } implicit final class ArrowAssoc[A](self : A) extends scala.AnyVal { @scala.inline def ->[B](y : B) : scala.Tuple2[A, B] = { /* compiled code */ } def →[B](y : B) : scala.Tuple2[A, B] = { /* compiled code */ } } implicit final class Ensuring[A](self : A) extends scala.AnyVal { def ensuring(cond : scala.Boolean) : A = { /* compiled code */ } def ensuring(cond : scala.Boolean, msg : => scala.Any) : A = { /* compiled code */ } def ensuring(cond : scala.Function1[A, scala.Boolean]) : A = { /* compiled code */ } def ensuring(cond : scala.Function1[A, scala.Boolean], msg : => scala.Any) : A = { /* compiled code */ } } implicit final class StringFormat[A](self : A) extends scala.AnyVal { @scala.inline def formatted(fmtstr : Predef.String) : Predef.String = { /* compiled code */ } } implicit final class any2stringadd[A](self : A) extends scala.AnyVal { def +(other : Predef.String) : Predef.String = { /* compiled code */ } } implicit final class RichException(self : scala.Throwable) extends scala.AnyVal { @scala.deprecated("use Throwable#getStackTrace", "2.11.0") def getStackTraceString : _root_.scala.Predef.String = { /* compiled code */ } } implicit final class SeqCharSequence(@scala.deprecated("will be made private", "2.12.0") val __sequenceOfChars : scala.collection.IndexedSeq[scala.Char]) extends java.lang.Object with java.lang.CharSequence { def length() : scala.Int = { /* compiled code */ } def charAt(index : scala.Int) : scala.Char = { /* compiled code */ } def subSequence(start : scala.Int, end : scala.Int) : java.lang.CharSequence = { /* compiled code */ } override def toString() : _root_.scala.Predef.String = { /* compiled code */ } } implicit final class ArrayCharSequence(@scala.deprecated("will be made private", "2.12.0") val __arrayOfChars : scala.Array[scala.Char]) extends java.lang.Object with java.lang.CharSequence { def length() : scala.Int = { /* compiled code */ } def charAt(index : scala.Int) : scala.Char = { /* compiled code */ } def subSequence(start : scala.Int, end : scala.Int) : java.lang.CharSequence = { /* compiled code */ } override def toString() : _root_.scala.Predef.String = { /* compiled code */ } } implicit val StringCanBuildFrom : scala.collection.generic.CanBuildFrom[Predef.String, scala.Char, Predef.String] = { /* compiled code */ } @scala.inline implicit def augmentString(x : Predef.String) : scala.collection.immutable.StringOps = { /* compiled code */ } @scala.inline implicit def unaugmentString(x : scala.collection.immutable.StringOps) : Predef.String = { /* compiled code */ } def print(x : scala.Any) : scala.Unit = { /* compiled code */ } def println() : scala.Unit = { /* compiled code */ } def println(x : scala.Any) : scala.Unit = { /* compiled code */ } def printf(text : Predef.String, xs : scala.Any*) : scala.Unit = { /* compiled code */ } implicit def tuple2ToZippedOps[T1, T2](x : scala.Tuple2[T1, T2]) : scala.runtime.Tuple2Zipped.Ops[T1, T2] = { /* compiled code */ } implicit def tuple3ToZippedOps[T1, T2, T3](x : scala.Tuple3[T1, T2, T3]) : scala.runtime.Tuple3Zipped.Ops[T1, T2, T3] = { /* compiled code */ } implicit def genericArrayOps[T](xs : scala.Array[T]) : scala.collection.mutable.ArrayOps[T] = { /* compiled code */ } implicit def booleanArrayOps(xs : scala.Array[scala.Boolean]) : scala.collection.mutable.ArrayOps.ofBoolean = { /* compiled code */ } implicit def byteArrayOps(xs : scala.Array[scala.Byte]) : scala.collection.mutable.ArrayOps.ofByte = { /* compiled code */ } implicit def charArrayOps(xs : scala.Array[scala.Char]) : scala.collection.mutable.ArrayOps.ofChar = { /* compiled code */ } implicit def doubleArrayOps(xs : scala.Array[scala.Double]) : scala.collection.mutable.ArrayOps.ofDouble = { /* compiled code */ } implicit def floatArrayOps(xs : scala.Array[scala.Float]) : scala.collection.mutable.ArrayOps.ofFloat = { /* compiled code */ } implicit def intArrayOps(xs : scala.Array[scala.Int]) : scala.collection.mutable.ArrayOps.ofInt = { /* compiled code */ } implicit def longArrayOps(xs : scala.Array[scala.Long]) : scala.collection.mutable.ArrayOps.ofLong = { /* compiled code */ } implicit def refArrayOps[T <: scala.AnyRef](xs : scala.Array[T]) : scala.collection.mutable.ArrayOps.ofRef[T] = { /* compiled code */ } implicit def shortArrayOps(xs : scala.Array[scala.Short]) : scala.collection.mutable.ArrayOps.ofShort = { /* compiled code */ } implicit def unitArrayOps(xs : scala.Array[scala.Unit]) : scala.collection.mutable.ArrayOps.ofUnit = { /* compiled code */ } implicit def byte2Byte(x : scala.Byte) : java.lang.Byte = { /* compiled code */ } implicit def short2Short(x : scala.Short) : java.lang.Short = { /* compiled code */ } implicit def char2Character(x : scala.Char) : java.lang.Character = { /* compiled code */ } implicit def int2Integer(x : scala.Int) : java.lang.Integer = { /* compiled code */ } implicit def long2Long(x : scala.Long) : java.lang.Long = { /* compiled code */ } implicit def float2Float(x : scala.Float) : java.lang.Float = { /* compiled code */ } implicit def double2Double(x : scala.Double) : java.lang.Double = { /* compiled code */ } implicit def boolean2Boolean(x : scala.Boolean) : java.lang.Boolean = { /* compiled code */ } implicit def Byte2byte(x : java.lang.Byte) : scala.Byte = { /* compiled code */ } implicit def Short2short(x : java.lang.Short) : scala.Short = { /* compiled code */ } implicit def Character2char(x : java.lang.Character) : scala.Char = { /* compiled code */ } implicit def Integer2int(x : java.lang.Integer) : scala.Int = { /* compiled code */ } implicit def Long2long(x : java.lang.Long) : scala.Long = { /* compiled code */ } implicit def Float2float(x : java.lang.Float) : scala.Float = { /* compiled code */ } implicit def Double2double(x : java.lang.Double) : scala.Double = { /* compiled code */ } implicit def Boolean2boolean(x : java.lang.Boolean) : scala.Boolean = { /* compiled code */ } @scala.annotation.implicitNotFound("Cannot prove that ${From} <:< ${To}.") sealed abstract class <:<[-From, +To]() extends scala.AnyRef with scala.Function1[From, To] with scala.Serializable { } implicit def $conforms[A] : Predef.<:<[A, A] = { /* compiled code */ } @scala.deprecated("use `implicitly[T <:< U]` or `identity` instead.", "2.11.0") def conforms[A] : Predef.<:<[A, A] = { /* compiled code */ } @scala.annotation.implicitNotFound("Cannot prove that ${From} =:= ${To}.") sealed abstract class =:=[From, To]() extends scala.AnyRef with scala.Function1[From, To] with scala.Serializable { } object =:= extends scala.AnyRef with scala.Serializable { implicit def tpEquals[A] : Predef.=:=[A, A] = { /* compiled code */ } } class DummyImplicit() extends scala.AnyRef { } object DummyImplicit extends scala.AnyRef { implicit def dummyImplicit : Predef.DummyImplicit = { /* compiled code */ } } }
2 型別轉換
implicit def byte2Byte(x : scala.Byte) : java.lang.Byte = { /* compiled code */ } implicit def short2Short(x : scala.Short) : java.lang.Short = { /* compiled code */ } implicit def char2Character(x : scala.Char) : java.lang.Character = { /* compiled code */ } implicit def int2Integer(x : scala.Int) : java.lang.Integer = { /* compiled code */ } implicit def long2Long(x : scala.Long) : java.lang.Long = { /* compiled code */ } implicit def float2Float(x : scala.Float) : java.lang.Float = { /* compiled code */ } implicit def double2Double(x : scala.Double) : java.lang.Double = { /* compiled code */ } implicit def boolean2Boolean(x : scala.Boolean) : java.lang.Boolean = { /* compiled code */ } implicit def Byte2byte(x : java.lang.Byte) : scala.Byte = { /* compiled code */ } implicit def Short2short(x : java.lang.Short) : scala.Short = { /* compiled code */ } implicit def Character2char(x : java.lang.Character) : scala.Char = { /* compiled code */ } implicit def Integer2int(x : java.lang.Integer) : scala.Int = { /* compiled code */ } implicit def Long2long(x : java.lang.Long) : scala.Long = { /* compiled code */ } implicit def Float2float(x : java.lang.Float) : scala.Float = { /* compiled code */ } implicit def Double2double(x : java.lang.Double) : scala.Double = { /* compiled code */ } implicit def Boolean2boolean(x : java.lang.Boolean) : scala.Boolean = { /* compiled code */ }
3 型別定義
Predef 定義了若干的型別及類型別名。為了鼓勵使用不可變集合,Predef 為最常用的不可變集合定義了別名:
type Class[T] = java.lang.Class[T]
type String = java.lang.String
type Map[A, +B] = scala.collection.immutable.Map[A, B]
type Set[A] = scala.collection.immutable.Set[A]
type Function[-A, +B] = scala.Function1[A, B]
val Map : scala.collection.immutable.Map.type = { /* compiled code */ }
val Set : scala.collection.immutable.Set.type = { /* compiled code */ }
支援型別推斷的其他一些Predef 型別。
我們經常使用a -> b(或等價的a → b)這種寫法:
object Test {
def main(args: Array[String]): Unit = {
val a = (1, "one")
val b = 1 -> "one"
val c = 1 → "one"
println(a) //輸出:(1,one)
println(b) //輸出:(1,one)
println(c) //輸出:(1,one)
val map = Map("one" -> 1, "two" -> 2)
println(map) //輸出:Map(one -> 1, two -> 2)
}
}
事實上,Scala 根本不知道a -> b 意味著什麼,因此上述方法並非沒有意義。這種“字面量”格式實際上運用了方法-> 和一個特殊的Scala 特性——隱式轉換。通過運用隱式轉換,我們可以在任意兩種型別值之間插入函式->。與此同時,由於a -> b 並不是元組的字面量語法,因此Scala 必須通過某些方式將該表示式轉化為元組(a, b)。
很明顯,->之所以能用,就是因為我們已經把->方法定義好了,也就是 ArrowAssoc的->方法,原始碼如下
implicit final class ArrowAssoc[A](self : A) extends scala.AnyVal {
@scala.inline
def ->[B](y : B) : scala.Tuple2[A, B] = { /* compiled code */ }
def →[B](y : B) : scala.Tuple2[A, B] = { /* compiled code */ }
}
在此只因關鍵字implicit起的作用,具體執行過程:
(1) 編譯器發現我們試圖對String 物件執行-> 方法(例如“ one” -> 1)。
(2) 由於String 未定義-> 方法,編譯器將檢查當前作用域中是否存在定義了該方法的隱式轉換。
(3) 編譯器發現了ArrowAssoc 類。
(4) 編譯器將建立ArrowAssoc 物件,並向其傳入one 字串。
(5) 之後,編譯器將解析表示式中的-> 1 部分程式碼,並確認了整個表示式的型別與Map.apply 方法的預期型別相吻合,即兩者均為pair 例項。
如果希望執行隱式轉換,那麼在宣告時必須使用implicit 關鍵字,能夠執行隱式轉換的無外乎兩類:構造方法中只接受單一引數的型別或者是隻接受單一引數的方法。
為了限定引數型別,Scala有了隱式證據<:<,在哪裡用到了呢?
package cn.com.tengen.test.obj
object Test {
def main(args: Array[String]): Unit = {
val map = Map("one" -> 1, "two" -> 2)
println(map.toMap) //輸出:Map(one -> 1, two -> 2)
val list1 = List((1,"aa"),(2,"bb"),(3,"cc"),(4,"dd"))
println(list1.toMap) //Map(1 -> aa, 2 -> bb, 3 -> cc, 4 -> dd)
val list2 = List(1,2,3,4)
println(list2.toMap) //丟擲異常
}
}
@scala.annotation.implicitNotFound("Cannot prove that ${From} <:< ${To}.")
sealed abstract class <:<[-From, +To]() extends scala.AnyRef with scala.Function1[From, To] with scala.Serializable {
}
package scala.collection
trait TraversableOnce[+A] extends scala.Any with scala.collection.GenTraversableOnce[A] {
...
def toMap[T, U](implicit ev: _root_.scala.Predef.<:<[A, scala.Tuple2[T, U]]): scala.collection.immutable.Map[T, U] = {
/* compiled code */
}
...
}
4 條件檢查方法
有時你希望斷言某條件為真,希望它“快速失敗”(尤其在測試時)。Predef 定義了許多有助於達到這個目的的方法。
• def assert(assertion: Boolean)
測試條件是否為真,如果不為真,丟擲java.lang.AssertionError 異常。
• def assert(assertion: Boolean, message: => Any)
類似前面的assert,但增加了一個可選引數,該引數將被轉為錯誤資訊字串。
• def assume(assertion: Boolean)
與assert 相同,但其表示當一段程式碼塊(如方法)正確時,條件才為真。
• def assume(assertion: Boolean, message: => Any)
類似前面的assume,但增加了一個可選引數,該引數將被轉為錯誤資訊字串。
• def require(requirement: Boolean)
與assume 相同,但根據Scaladoc,其含義是呼叫方是否滿足某些條件,也可以表示某個實現不能得出特定的結果。
• def require(requirement: Boolean, message: => Any)
類似前面的require,但增加了一個可選引數,該引數將被轉為錯誤資訊字串。
5 輸入輸出方法
Scala把資料列印到控制檯,這是我們經常做的操作,其實他也是Predef定義的。Predef 為我們提供了四種將字串列印到stdout 的形式。
def print(x : scala.Any) : scala.Unit = { /* compiled code */ }
def println() : scala.Unit = { /* compiled code */ }
def println(x : scala.Any) : scala.Unit = { /* compiled code */ }
def printf(text : Predef.String, xs : scala.Any*) : scala.Unit = { /* compiled code */ }
• def print(x: Any): Unit
將x 轉為字串,然後寫到標準輸出,結尾不會自動新增換行。
• def printf(format: String, xs: Any*): Unit
用format 和其他引數xs 對printf 風格的字串進行格式化,然後將結果寫到標準輸出,結尾不會自動新增換行。
• def println(x: Any): Unit
類似print,但結尾會自動新增換行。
• def println(): Unit
向標準輸出列印空行。
在老的版本中(2.12之前)Predef提供了相當多的輸入方法:
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readLine() : DeprecatedPredef.super[Predef/*scala.Predef*/].String = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readLine(text : DeprecatedPredef.super[Predef/*scala.Predef*/].String, args : scala.Any*) : _root_.scala.Predef.String = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readBoolean() : scala.Boolean = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readByte() : scala.Byte = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readShort() : scala.Short = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readChar() : scala.Char = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readInt() : scala.Int = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readLong() : scala.Long = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readFloat() : scala.Float = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readDouble() : scala.Double = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readf(format : DeprecatedPredef.super[Predef/*scala.Predef*/].String) : scala.List[scala.Any] = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readf1(format : DeprecatedPredef.super[Predef/*scala.Predef*/].String) : scala.Any = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readf2(format : DeprecatedPredef.super[Predef/*scala.Predef*/].String) : scala.Tuple2[scala.Any, scala.Any] = { /* compiled code */ }
@scala.deprecated("use the method in `scala.io.StdIn`", "2.11.0")
def readf3(format : DeprecatedPredef.super[Predef/*scala.Predef*/].String) : scala.Tuple3[scala.Any, scala.Any, scala.Any] = { /* compiled code */ }
• def readBoolean(): Boolean
從標準輸入的一個整行中讀取一個Boolean 值。
• def readByte(): Byte
從標準輸入的一個整行中讀取一個Byte 值。
• def readChar(): Char
從標準輸入的一個整行中讀取一個Char 值。
• def readDouble(): Double
從標準輸入的一個整行中讀取一個Double 值。
• def readFloat(): Float
從標準輸入的一個整行中讀取一個Float 值。
• def readInt(): Int
從標準輸入的一個整行中讀取一個Int 值。
• def readLine(text: String, args: Any*): String
向標準輸出中列印格式化的提示文字,並從標準輸入中讀取一整行字串。
• def readLine(): String
從標準輸入中讀取一整行字串。
• def readLong(): Long
從標準輸入的一個整行中讀取一個Long 值。
• def readShort(): Short
從標準輸入的一個整行中讀取一個Short 值。
• def readf(format: String): List[Any]
根據format 中的區分符號,從標準輸入中讀取格式化輸入。
• def readf1(format: String): Any
根據format 中的區分符號,從標準輸入中讀取格式化輸入。並根據format 的指定,返回提取的第一個值。
• def readf2(format: String): (Any, Any)
根據format 中的區分符號,從標準輸入中讀取格式化輸入。並根據format 的指定,返回提取的前兩個值。
• def readf3(format: String): (Any, Any, Any)
根據format 中的區分符號,從標準輸入中讀取格式化輸入。並根據format 的指定,返回提取的前三個值。
在輸入時也可以選擇Java的方式:
val read:Scanner = new Scanner(System.in)
val line = read.nextLine()
val b = read.nextByte()
val s = read.nextShort()
val i = read.nextInt()
val f = read.nextFloat()
val d = read.nextDouble()
val l = read.nextLong()
val bool = read.nextBoolean()
6 雜項方法
1 ???
在一個尚未實現的方法的方法體中呼叫。它為方法提供了具體的定義,允許編譯器將方法所屬的型別視為具體(與抽象對應)的類。然而,如果呼叫該方法,就會丟擲scala.NotImplementedError 異常。原始碼如下:
def ??? : scala.Nothing = { /* compiled code */ }
2 identity
直接返回引數x。在將方法傳給組合器(combinator)時,如果不需要進行修改,就可以用它。例如:在一個工作流程中,我們通過給map 傳入一個函式來對集合元素進行轉化。有時我們不需要做任何轉化,你可以傳入identity。原始碼如下:
@scala.inline
def identity[A](x : A) : A = { /* compiled code */ }
3 implicitly
當隱式引數列表使用簡寫[T:M] 時,編譯器會新增形式為(implicit arg: M[T]) 的隱式引數列表(實際名稱不是arg,而是編譯器合成的唯一名稱)。呼叫implicitly 可以返回引數arg。原始碼如下:
@scala.inline
def implicitly[T](implicit e : T) : T = { /* compiled code */ }
看一個例子:
package cn.com.tengen.test.obj
class Test{
}
case class MyList[A](list: List[A]) {
def sortBy1[B](f: A => B)(implicit ord: Ordering[B]): List[A] =
list.sortBy(f)(ord)
def sortBy2[B : Ordering](f: A => B): List[A] =
list.sortBy(f)(implicitly[Ordering[B]])
}
object Test {
def main(args: Array[String]): Unit = {
val list = MyList(List(1,3,5,2,4))
val l1 = list sortBy1 (i => -i)
val l2 = list sortBy2 (i => -i)
println(l1)
println(l2)
}
}
有些集合提供了一些排序方法,List.sortBy 便是其中之一。List.sortBy 方法的第一個引數型別為函式,該輸入函式能夠將函式的輸入引數轉化為另一個滿足math.Ordering 條件的型別。而math.Ordering 是與Java 中的Comparable抽象等同的型別。List.sortBy 方法的另一個引數則為隱式引數,該引數知道如何對型別B 的例項進行排序。 MyList 類提供了兩種方式編寫像sortBy 型別的方法。第一種實現:sortBy1 方法應用了我們已知的語法。該方法接受一個額外的型別為Ordering[B] 的隱式值作為其輸入。呼叫sortBy1 方法時,在當前作用域中一定存在某一Ordering[B] 的物件例項,該例項清楚地知道如何對我們所需要的B 型別物件進行排序。我們認為B 的界限被“上下文”所限定,在這個例子中,上下文限定了B 對例項進行排序的能力。 由於這種Scala 方言應用非常普遍,因此Scala 提供了一個簡化版的語法,這正是第二類實現 sortBy2 所使用的語法。型別引數B : Ordering被稱為 上下文定界( context bound), 它暗指第二個引數列表(也就是那個隱式引數列表)將接受Ordering[B] 例項。 不過,我們仍需要在方法中訪問Ordering 物件例項。由於在原始碼中我們不再明確地宣告Ordering 物件例項,因此這個例項沒有自己的名稱。針對這種現象我們該怎麼辦呢?Predef.implicitly 方法幫我們解決了這個問題。implicitly 方法會對傳給函式的所有標記為隱式引數的例項進行解析。請注意implicitly 方法所需要的型別簽名,在本例中Ordering[B] 是其型別簽名。 4.Pair 與 Triple Pair是一個二元組,Triple是一個三元組 原始碼:
@scala.deprecated("use built-in tuple syntax or Tuple2 instead", "2.11.0")
type Pair[+A, +B] = scala.Tuple2[A, B]
@scala.deprecated("use built-in tuple syntax or Tuple2 instead", "2.11.0")
object Pair extends scala.AnyRef {
def apply[A, B](x : A, y : B) : scala.Tuple2[A, B] = { /* compiled code */ }
def unapply[A, B](x : scala.Tuple2[A, B]) : scala.Option[scala.Tuple2[A, B]] = { /* compiled code */ }
}
@scala.deprecated("use built-in tuple syntax or Tuple3 instead", "2.11.0")
type Triple[+A, +B, +C] = scala.Tuple3[A, B, C]
@scala.deprecated("use built-in tuple syntax or Tuple3 instead", "2.11.0")
object Triple extends scala.AnyRef {
def apply[A, B, C](x : A, y : B, z : C) : scala.Tuple3[A, B, C] = { /* compiled code */ }
def unapply[A, B, C](x : scala.Tuple3[A, B, C]) : scala.Option[scala.Tuple3[A, B, C]] = { /* compiled code */ }
}
5. Map與Set 我們先可一個例子:
object Test {
def main(args: Array[String]): Unit = {
val map = Map(1->"aaa",2->"BBB")
val set = Set(1,2,33,44,44,6)
println(map)
println(set)
}
}
這裡我們用的Map和Set都是Predef中的兩個屬性,而並沒有直接匯入scala.collection.immutable.Map和scala.collection.immutable.Set,看原始碼:
type Map[A, +B] = scala.collection.immutable.Map[A, B]
type Set[A] = scala.collection.immutable.Set[A]
val Map : scala.collection.immutable.Map.type = { /* compiled code */ }
val Set : scala.collection.immutable.Set.type = { /* compiled code */ }