7.scala初识 柯里化、隐式参数、隐式转换、视图边界、上界、下界、协变、逆变

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangguohe/article/details/79007502

1.前言:

学过java我们都知道,java中的继承是对类的增强,java中的代理、装饰是对对象方法的增强。而在scala中,隐式转换和隐式参数是Scala中两个非常强大的功能,隐式的对类的方法进行增强,丰富现有类库的功能 。利用隐式转换和隐式参数,你可以提供优雅的类库,对类库的使用者隐匿掉那些枯燥乏味的细节。

而所谓的隐式转化函数,是指那种以implicit关键字声明的带有单个参数的函数。在了解隐式参数及转换之前,有必要提及一下柯里化。下面,我会通过文字与代码相结合的方式供大家更好的理解这些概念及入门使用,谬论之处欢迎指正!

2.柯里化

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。

更直观的对比:

def m1(x:Int,y:Int)=x+y       m1(2,3)    =5  正常方法

def m2(x:Int)(y:Int)=x+y     m2(2)(3)    =5   柯里化

至于柯里化的好处请参考:http://blog.csdn.net/wangguohe/article/details/79007737

3.隐式参数

package lesson11

/*
    隐式的都是要放在object里面,因为都是直接调用的,而不是去new的
 */
object Test {
  def k1(x:Int)(y:Int):Int= x+ y
  //implicit 隐式的
  //先找 全局 里面是否 有 int 类型的隐式值
  //如果有就要全局里面的,如果没有就看局部的,局部有就要局部的
  //如果局部没有就报错了。

  //全局只能有一个隐式参数满足条件,多个条件如果都满足,那么就会报错
 implicit val xiaoma:Int=10
//  implicit val xiaoma2:Int=9
  def k2(x:Int)(implicit y:Int=6)= x * y
  def main(args: Array[String]): Unit = {
//    val kresult = k1(5)(6)   30
    val kresult = k2(8)
    println(kresult)  //80
  }

}

4.隐式转换

情景一:当某个对象去调用某个方法的时候,如果这个对象没有这个方法,就会发生隐式转换。

案例1:man是没有fly的功能,但是通过隐式转换,将Man对象转换为了SuperMan的对象,他可以调用此功能。

package lesson13

class Man {}
class SuperMan{
  def fly(){
    println("超人会飞")
  }
}
object Test{
  implicit  def man2Superman(man:Man):SuperMan=new SuperMan()
  def main(args: Array[String]): Unit = {
     val man = new Man()
         man.fly()
  }
}
案例2:File本身是没有read功能的,但是通过隐式转换,将File对象转换为RichFile对象,他也调用了read功能。
package lesson12

import java.io.File
import scala.io.Source
object Test {
  def main(args: Array[String]): Unit = {
    implicit def file2RichFile(file:File):RichFile=new RichFile(file)
    val file = new File("D:\a.txt").read()
    println(file)
  }
}
class RichFile(f:File) {
  def read():String={
    Source.fromFile(f).mkString
  }
}
可以发现以上两种案例的区别就是第一个转换时没有将自己作为转换后的类的参数,而第二个file则作为了参数。

思考1?我们用过1 to 10,其本质是 1.to(10), 1 是自动匹配为Int类型,那Int有to方法吗?实现Int有to方法的方式又是怎样的呢?  (implicit def intWrapper(x: Int)  = new runtime.RichInt(x))

思考2?有没有发现隐式转换与java的那个设计模式比较像呢?(装饰者模式)


情景二:某个对象去调用某个方法,这个对象也确实有这个方法,只不过传入的参数类型不匹配,就会发生隐式转换。

案例3:买票方法buySpecialTicket传入的参数是特殊人群SpecialPerson,但是调用的时传入的参数不是SpecialPerson类型。

package lesson14


//定义了一个类:  代表的是特殊人群
class SpecialPerson(var name:String){}
//学生
class Student(val name:String){}
//老人
class Older(val name:String){}
//一般的普通人
class Worker(val name:String){}

class TicketHouse{
  var num:Int=1;
  def buySpecialTicket(p:SpecialPerson)={
    num+=1
    println("T-"+ num )
  }

}

object Test{
  implicit  def object2SpecialPerson(obj: Object):SpecialPerson={
    if(obj.getClass == classOf[Student]){  //判断这个对象是不是学生
    val student = obj.asInstanceOf[Student]
      new SpecialPerson(student.name)
    }else if(obj.getClass  == classOf[Older]){
      val older = obj.asInstanceOf[Older]
      new SpecialPerson(older.name)
    }else{
      None
    }
  }

  def main(args: Array[String]): Unit = {
    val house = new TicketHouse()
    val worker = new Worker("jianglaoshi")
    val student = new  Student("xiaoma")
    val older = new Older("wukong")
    house.buySpecialTicket(older)
  }
}
情景三:视图边界  A <% B

 A <% B  左侧必须是右侧的子类, 如果A 不是B的子类,这个时候也会发生隐式转换,把A 转换成为 B。

案例4:本来有个方法人只能跟人交朋友,人也想跟狗交朋友,把够隐式转换成为人。

class Person(var name:String) {
  def sayHello=println("hello ,I'm "+ name)

  def makeFriends(p:Person): Unit ={
    sayHello
    p.sayHello
    println("我们就是好朋友")
  }
}

class Student(name:String) extends Person(name)
class Dog(var name:String)

class Worker(val name:String)

class Party[T <% Person](p1:T,p2:T){
  def play(): Unit ={
    p1.makeFriends(p2)
  }
}

object Test{
  implicit def dog2Person(obj:Object):Person={
    if(obj.isInstanceOf[Dog]){
      val dog_ = obj.asInstanceOf[Dog]
      new Person(dog_.name)
    }else {
      None
    }
  }
  def main(args: Array[String]): Unit = {
    val sunli = new Student("孙俪")
    val zhouxu = new Student("周迅")

    val dog = new Dog("哮天犬")

    val worker = new Worker("malaoshi")

    val party = new Party[Person](sunli,dog)
    party.play()
  }


}
接下来,我们要讲到的上界、下界、协变、逆变就结合隐式转换来进行理解。

5.上界、下界、协变、逆变

上界:T <: ...   T 是...的类型或子类

案例5:比颜值。

package lesson15

class Pair[T <:Comparable[T]] {
  def shuai(first:T,second:T):T={
    if(first.compareTo(second)  > 0) first else second
  }
}

object Test{
  def main(args: Array[String]): Unit = {
    val pair = new Pair[Boy]
    val shuai = pair.shuai(new Boy("段奕宏",99),new Boy("王千源",88))
    print(shuai)
  }
}
class Boy(var name:String,var faceValue:Int) extends Comparable[Boy]{
  override def compareTo(o: Boy): Int = {
    (this.faceValue  -  o.faceValue)
  }

  override def toString: String = {
    s"name:${name}  value:${faceValue}"
  }
}
下界:T >: ...   T是...的类型或父类。

案例6:取身份证,定义了下界Child, GrangFather Father 能取走我的身份证。

class GrandFather
class Father extends  GrandFather
class Child extends Father

class Tongshi

object  Test{
  def getIDCard[T >: Child](person:T): Unit ={
    println("好的,身份证就交给你了!!")
  }

  def main(args: Array[String]): Unit = {
    getIDCard[GrandFather](new GrandFather)
  }
}

协变:本来要的是父类,但是子类来了也可以。

逆变:本来来的是子类,但是父类来了也可以。

由于概念非常简单,这里直接上代码取体会。

案例7:

class QingTong
class BaiJin extends  QingTong
class WangZhe extends BaiJin
class Worker
      //协变
class Card[+T](val name:String)

object Test{
  def daSai(card:Card[QingTong]): Unit ={
    println("欢迎参加王者荣耀大赛")
  }

  def main(args: Array[String]): Unit = {
    val c1 = new Card[QingTong]("malaoshi")
    val wangzhe = new Card[WangZhe]("jianglaoshi")
   // val jia = new Card[Worker]("lurenjia")
   // daSai(wangzhe)
  }
}
案例8:
class Master
class Professinal extends  Master
class Student

class Card[-T](val name:String)

object Test{
  def shangHaiDaShiSai(card:Card[Professinal]): Unit ={
    println("欢迎你来到上海大师赛")
  }
  def main(args: Array[String]): Unit = {

    val lc = new Card[Professinal]("梁文博")
    val ac = new Card[Master]("奥沙利文")
    val student = new Student
   // shangHaiDaShiSai(student)

  }
}













 










展开阅读全文

没有更多推荐了,返回首页