從頭學習大數據培訓課程 scala 對象與函數式編程(四)scala 基礎 4
隱式轉換
作用:能夠豐富現有類庫的功能,對類的方法進行增強
隱式轉換函數
以implicit關鍵字聲明並帶有單個參數的函數
比如1 to 10其實是調用的1.to(10)這個方法
但是在Int類中並沒有to這個方法int 的to方法實際上是調用RichInt里的intWrapper方法,最終調用的是RichInt里的to方法
intWrapper就是以implicit關鍵字聲明並帶有單個參數的函數,intWrapper就是一個隱式轉換函數predef這個類就是預定義的predefine的簡寫在shell中用:implicit -v來查看,默認有多少個隱式轉換函數
在2.11.8中有69個隱式轉換,scala升級比較快所以其它版本可能不同隱式轉換函數其實用到了裝飾模式
裝飾模式對應的是門面模式
隱式轉換練習:
給代表文件地址的字元串增加一個可以讀文件的功能import scala.io.Source
class ImplicitFunctionDemo(val path:String) {def read():String = {Source.fromFile(path).mkString} }object ImplicitFunctionDemo{def main(args: Array[String]): Unit = {val path = "C:\Users\Leo.He\Desktop\抽取項目描述.txt"
val content: String = new ImplicitFunctionDemo(path).read() println(content) } }這是一個顯示的調用並不是一個隱式的調用,這是我們平時開發過程中常用的方法
隱式轉換函數的實現方法
1.首先在MyPredef寫一個String的隱式轉換函數object MyPredef {
implicit def pathStringToImplicitFunction(path:String) = new ImplicitFunctionDemo(path) }2.然後修改剛才的類為隱式轉換的調用方式,在使用隱式轉換中String類型的path變數就有了read方法,這個read實現上是ImplicitFunctionDemo的read。這個轉換過程是由MyPredef里的隱式轉換函數完成的
import scala.io.Source
class ImplicitFunctionDemo(val path:String) {def read():String = {Source.fromFile(path).mkString} }
object ImplicitFunctionDemo{def main(args: Array[String]): Unit = {val path = "C:\Users\Leo.He\Desktop\抽取項目描述.txt"val content: String = new ImplicitFunctionDemo(path).read() println(content)import MyPredef.pathStringToImplicitFunctionval content1 = path.read() println(content1) } }隱式轉換與柯里化的使用shell中柯里化與隱式轉換使用的例子
/**
* 這裡用到了隱式轉換、隱式值、柯里化(隱式參數)、內部類、泛型、特質、比較的方法、重寫toString方法* 首先import OrderingDemo.OrderStudent
* OrderStudent是Ordering[HainiuStudent]的子類 * 所以demo.comp() 柯里化方法(def comp()(implicit ord:Ordering[HainiuStudent])) 第二個參數會匹配到OrderStudent * 所以ord的值傳入的是OrderStudent * ord.gt(v1,v2)調用的是OrderStudent的gt方法也就是ordering的gt方法(def gt(x: T, y: T): Boolean = compare(x, y) > 0) * ordering的gt方法中調用的是compare,但OrderStudent是ordering的子類實現,所以調用的是orderStudent的compare方法 * 由OrderStudent的compare方法返回會的正負值決定了返回true還是false,(Boolean = compare(x, y) > 0) 大於0是true小於0是false * demo.comp()(def comp()(implicit ord:Ordering[T]))方法返回比較之後的對象 * println(student)列印了對象重寫的toString方法(override def toString: String = s"name:$name,age:$age")的返回值 */object OrderingDemo {
implicit object OrderStudent extends Ordering[HainiuStudent]{override def compare(x: HainiuStudent, y: HainiuStudent): Int = if(x.age > y.age) 1 else -1 } } class CompareDemo[T:Ordering](val v1:T,val v2:T){def comp()(implicit ord:Ordering[T]) = if(ord.gt(v1,v2)) v1 else v2}object CompareDemo{def main(args: Array[String]): Unit = {import OrderingDemo.OrderStudentval s1 = new HainiuStudent("牛1",24)val s2 = new HainiuStudent("牛2",23)val demo = new CompareDemo[HainiuStudent](s1,s2) // val demo = new CompareDemo(s1,s2) //簡寫的方式
val student: HainiuStudent = demo.comp() println(student) } } class HainiuStudent(val name:String,val age:Int){override def toString: String = s"name:$name,age:$age" }泛型:泛型就是不確定的類型,可以在類或方法不確實傳入類型時使用,可以提高代碼的靈活性和復用性scala中泛型的用法和java中差不多,但是會有一些自己獨特的語法
比如說ordering中泛型的一些特殊符號
這個叫ViewBound
這個叫UpperBound
泛型:
[B <: A] UpperBound 上界,B類型的父類是A類型[B >: A] LowerBound 下界,B類型的子類是A類型
[B <% A] ViewBound B類型轉換成A類型,需要一個隱式轉換函數[B : A] ContextBound 需要轉換成A[B]類型,需要一個隱式轉換的類型[-A] 逆變,作為參數類型,T是A的子類[+B] 協變,作為返回類型,T是B的父類UpperBound
class UpperBoundDemo[T <: Comparable[T]] {
def choose(a:T,b:T):T = { if(a.compareTo(b) > 0) a else b} }object UpperBoundDemo{def main(args: Array[String]): Unit = {
val u = new UpperBoundDemo[HaniuEngineer]val h1 = new HaniuEngineer("牛大",20)val h2 = new HaniuEngineer("牛二",22) println(u.choose(h1,h2)) } } class HaniuEngineer(val name:String,val age:Int) extends Comparable[HaniuEngineer]{override def compareTo(o: HaniuEngineer): Int = {this.age - o.age //SCALA中訪問本類的屬性也可以用this }override def toString: String = {s"${name}我年紀大" } }ViewBound
class ViewBoundDemo[T <% Ordered[T]] {
def choose(work1:T,work2:T):T={ if(work1 > work2) work1 else work2} }object ViewBoundDemo{def main(args: Array[String]): Unit = {import MyPredef.selectWorkval demo = new ViewBoundDemo[HainiuWork]val work1 = new HainiuWork("金融",20000,10)val work2 = new HainiuWork("互聯網",20000,6) print(demo.choose(work1,work2)) } } class HainiuWork(val company:String,val money:Int,val holiday:Int){override def toString: String = {s"go to $company,happy holiday $holiday" } }隱式轉換函數實現
object MyPredef {
implicit val selectWork = (s:HainiuWork) => new Ordered[HainiuWork]{override def compare(that: HainiuWork) = { if(s.money == that.money){s.holiday - that.holiday}else{s.money - that.money} } } }ContextBound
//T:Ordering 需要一個隱式轉換是Ordering[T]類型的 class ContextBoundDemo[T:Ordering] {
def choose(work1:T,work2:T):T={val ord:Ordering[T] = implicitly[Ordering[T]] //import MyPredef.SelectWorkObject Ordering[HainiuWork] //implicitly[Ordering[HainiuWork]](implicit e: Ordering[HainiuWork]) = e //(implicit e: Ordering[T]) = e //def implicitly[HainiuWork](implicit e: HainiuWork) = e //val ord:Ordering[HainiuWork] = MyPredef.SelectWorkObject if(ord.gt(work1,work1)) work1 else work2} }object ContextBoundDemo{def main(args: Array[String]): Unit = {import MyPredef.SelectWorkObjectval demo = new ContextBoundDemo[HainiuWork]val work1 = new HainiuWork("金融",20000,6)val work2 = new HainiuWork("互聯網",19000,6) println(demo.choose(work1,work2)) } }隱式轉換類型實現
object MyPredef {
implicit object SelectWorkObject extends Ordering[HainiuWork]{override def compare(s: HainiuWork, that: HainiuWork): Int = { if(s.money == that.money){s.holiday - that.holiday}else{s.money - that.money} } } }版權聲明:原創作品,允許轉載,轉載時務必以超鏈接的形式表明出處和作者信息。否則將追究法律責任。來自海牛學院-青牛
推薦閱讀:
※分答和在行到底值不值1個億美金?
※「互聯網金融&大數據風控」結合的九大維度
※大數據計數原理1+0=1這你都不會算(九)No.64
※數據分析不只Tableau,這款國產工具也能扛上一扛!