Scala泛型、隐式转换和隐式参数、视图介绍、Scala中的上界、下界、结合柯里化进行隐式转换

二、泛型

一、Scala泛型 
1. 泛型介绍 
泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时才被确定,泛型可以有效地增强程序的适用性,使用泛型可以使得类或方法具有更强的通用性。泛型的典型应用场景是集合及集合中的方法参数,可以说同java一样,scala中泛型无处不在,具体可以查看scala的api。 
2. 泛型类、泛型方法 
泛型类:指定类可以接受任意类型参数。 
泛型方法:指定方法可以接受任意类型参数。 
3. 案例 
案例一:

package cn.toto.gen

/**
  * Created by toto on 2017/7/1.
  * 下面的意思就是表示只要是Comparable就可以传递,下面是类上定义的泛型
  */
/*class MrRight[T <:Comparable[T]] {
  //定义一个选择方法,实现选择的功能
  def choose(first : T,second : T) : T = {
    if(first.compareTo(second) > 0) first else second
  }
}*/

/**
  * 在类上定义泛型可以,当然,也可以在方法上定义泛型,定义的方式如下:
  */
class MrRight {
  def choose[T <: Comparable[T]](first:T,second:T) : T = {
    if(first.compareTo(second) > 0) first else second
  }
}

object MrRight {
  def main(args: Array[String]): Unit = {
//    //如果是类上定义的泛型,通过下面的方式调用
//    val mr = new MrRight[Boy]
//    val b1 = new Boy("laoduan",99)
//    val b2 = new Boy("laozhao",9999)
//    val boy = mr.choose(b1,b2)
//    //结果是:laozhao
//    println(boy.name)

    //如果是在方法上定义的泛型,可以使用下面的方式:
    var mr = new MrRight
    val b1 = new Boy("laoduan",99)
    val b2 = new Boy("laozhao",9999)
    val boy = mr.choose[Boy](b1,b2)
    //结果同样是:laozhao
    println(boy.name)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

案例二:

package cn.toto.scala.enhance

/**
  * Created by toto on 2017/7/1.
  * 泛型类,泛型方法
  * 泛型用于指定方法或类可以接受任意类型参数
  * 参数在实际使用时才被确定
  * 泛型可以有效地增强程序的适用性
  * 使用泛型可以使用得类或方法具有更强的通用性
  */
//泛型类    F S T是类型的参数
class GenericClass[F,S,T](val f:F,val s:S,val t:T)
object GenericDemo {

  //泛型方法
  def getData[T](list:List[T]) = list(list.length/2)

  /**
    * 运行结果:
    * 26
    * 3
    */
  def main(args : Array[String]): Unit = {
    //实例化方式1
    val gc1 = new GenericClass("lisha",26,"beijing")
    //实例化方式2
    val gc2 = new GenericClass[String,String,Int]("lisha","beijing",26)

    println(getData(List("lisha",26,"beijing")))

    val t = getData[Int] _
    println(t(List(1,2,3,4,5)))
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

二、 隐式转换和隐式参数

1. 概念 
隐式转换和隐式参数是Scala中两个非常强大的功能,利用隐式转换和隐式参数,你可以提供优雅的类库,对类库的使用者隐匿掉那些枯燥乏味的细节。 
2. 作用 
隐式的对类的方法进行增强,丰富现有类库的功能 
3. 隐式转换函数 
是指那种以implicit关键字声明的带有单个参数的函数。

可以通过::implicit –v这个命令显示所有做隐式转换的类。 
4. 隐式转换例子

package cn.toto.impli

import java.io.File
import scala.io.Source

/**
  * 这个案例是为了一下读出文件中的内容,目的类似通过下面的read方法直接读取出其中的内容:
  * var file = new File("E:\\wordcount\\input\\1.txt");
    var contents = file.read();
  *
  * Created by toto on 2017/7/1.
  * 隐式的增强File类的方法
  */
class RichFile(val from : File){
  //定义一个read方法,返回
  def read() : String = Source.fromFile(from.getPath).mkString
}

object RichFile {
  //隐式转换方法(将原有的File类型转成了file类型,在用的时候需要导入相应的包)
  implicit def file2RichFile(from : File) = new RichFile(from)
}

object MainApp {
  def main(args: Array[String]): Unit = {
    val file = new File("E:\\wordcount\\input\\a.txt");
    //装饰模式,显示的增强(本来想实现:val contents = file.read(),但是却使用RichFile的方式,所以是显示的增强)
    val rf = new RichFile(file)
    val contents = rf.read();

    //目的是使用File的时候不知不觉的时候直接使用file.read()方法,所以这里就要做隐式转换

    //导入隐式转换,._将它下满的所有的方法都导入进去了。 导包的代码,可以
    import RichFile._
    //这里没有的read()方法的时候,它就到上面的这一行中的找带有implicit的定义方法
    var content = new File("E:\\wordcount\\input\\a.txt").read
    println()

    //import RichFile.file2RichFile
    //println(file2RichFile(new File("E:\\wordcount\\input\\1.txt")).read)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
package cn.toto.scala

import java.awt.GridLayout

/**
  * Created by ZX on 2015/11/13.
  */
object ImplicitContext{
  //implicit def girl2Ordered(g : Girl) = new Ordered[Girl]{
  //  override def compare(that: Girl): Int = if (g.faceValue > that.faceValue) 1 else -1
  //}

  implicit object OrderingGirl extends Ordering[Girl]{
    override def compare(x: Girl, y: Girl): Int = if (x.faceValue > y.faceValue) 1 else -1
  }
}

class Girl(var name: String, var faceValue: Double){
  override def toString: String = s"name : $name, faveValue : $faceValue"
}

//class MissRight[T <% Ordered[T]](f: T, s: T){
//  def choose() = if(f > s) f else s
//}
//class MissRight[T](f: T, s: T){
//  def choose()(implicit ord: T => Ordered[T]) = if (f > s) f else s
//}

class MissRight[T: Ordering](val f: T, val s: T){
  def choose()(implicit ord: Ordering[T]) = if(ord.gt(f, s)) f else s
}

object MissRight {
  def main(args: Array[String]) {
    import ImplicitContext.OrderingGirl
    val g1 = new Girl("yuihatano", 99)
    val g2 = new Girl("jzmb", 98)
    val mr = new MissRight(g1, g2)
    val result = mr.choose()
    println(result)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

视图介绍

隐含参数和方法也可以定义隐式转换,称作视图。视图的绑定从另一个角度看就是implicit的转换。主要用在两个场合: 
 当一个T类型的变量t要装换成A类型时 
 当一个类型T的变量t无法拥有A类型的a方法或变量时 
其实视图的绑定是为了更方便的使用隐式装换 
用符号 <% 表示。

Scala中的上界、下界

1.上界、下界介绍 
在指定泛型类型时,有时需要界定泛型类型的范围,而不是接收任意类型。比如,要求某个泛型类型,必须是某个类的子类,这样在程序中就可以放心的调用父类的方法,程序才能正常的使用与运行。此时,就可以使用上下边界Bounds的特性; 
Scala的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类;

(1) U >: T

这是类型下界的定义,也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)。

(2) S <: T

这是类型上界的定义,也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类)。

下面是视图介绍和上界、下界的示例代码: 
下面定义两个类

package cn.toto.gen

/**
  * Created by toto on 2017/7/1.
  */
class Boy(val name : String,var faceVlue : Int) extends Comparable[Boy] {
  override def compareTo(o: Boy): Int = {
    this.faceVlue - o.faceVlue
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
package cn.toto.gen

/**
  * Created by toto on 2017/7/1.
  */
class Girl(val name:String,var faceValue:Int) {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
这里写代码片
  • 1
package cn.toto.gen

import java.awt.GridLayout
import java.io.File

import cn.toto.impli.RichFile

/**
  * Created by ZhaoXing on 2016/8/18.
  */
object MyPreDef {
  //针对viewbound方式的
//  implicit def girl2Ordered(g : Girl) = new Ordered[Girl] {
//    override def compare(that: Girl): Int = {
//      g.faceValue - that.faceValue
//    }
//  }

  //针对Ordering类型的
  implicit object Girl2Ordering extends Ordering[Girl] {
    override def compare(x: Girl, y: Girl): Int = {
      x.faceValue - y.faceValue
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
package cn.toto.gen

/**
  * Created by toto on 2017/7/1.
  * 下面的意思就是表示只要是Comparable就可以传递,下面是类上定义的泛型
  */
/*class MrRight[T <:Comparable[T]] {
  //定义一个选择方法,实现选择的功能
  def choose(first : T,second : T) : T = {
    if(first.compareTo(second) > 0) first else second
  }
}*/

/**
  * 在类上定义泛型可以,当然,也可以在方法上定义泛型,定义的方式如下:
  */
class MrRight {
  def choose[T <: Comparable[T]](first:T,second:T) : T = {
    if(first.compareTo(second) > 0) first else second
  }
}

object MrRight {
  def main(args: Array[String]): Unit = {
//    //如果是类上定义的泛型,通过下面的方式调用
//    val mr = new MrRight[Boy]
//    val b1 = new Boy("laoduan",99)
//    val b2 = new Boy("laozhao",9999)
//    val boy = mr.choose(b1,b2)
//    //结果是:laozhao
//    println(boy.name)

    //如果是在方法上定义的泛型,可以使用下面的方式:
    var mr = new MrRight
    val b1 = new Boy("laoduan",99)
    val b2 = new Boy("laozhao",9999)
    val boy = mr.choose[Boy](b1,b2)
    //结果同样是:laozhao
    println(boy.name)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
package cn.toto.gen

/**
  * Created by toto on 2017/7/1.
  */
//viewbound必须存在一个隐式转换方法,视图界定,必须有一个隐式转换的方法
//class MissRight[T <% Ordered[T]] {
//  def choose(first:T,second : T) : T = {
//    //这里的之所以可以用'>',是因为这里的T可以转换成Order的类型
//    if(first > second) first else second
//  }
//}

//如果使用上下文界定,必须存在一个隐式转换的值,特点是使用Ording,但是不需要使用Ordering[T]
class MissRight[T : Ordering] {
  def select(first : T,second : T) : T = {
    //通过使用implicitly转换类型
    val ord = implicitly[Ordering[T]]
    if(ord.gt(first,second)) first else second
  }
}

object MissRight {
  def main(args: Array[String]): Unit = {
    def main(args: Array[String]): Unit = {
      //这里是使用viewbound方式的。
//      import MyPreDef._
//      val mr = new MissRight[Girl]
//      val g1 = new Girl("ab",90)
//      val g2 = new Girl("aaa",999)
//      val g = mr.choose(g1,g2)
//      println(g.name)

      //这里是针对Order类型的
      import MyPreDef._
      val mr = new MissRight[Girl]
      val g1 = new Girl("ab",90)
      val g2 = new Girl("aaa",999)
      val g = mr.select(g1,g2)
      println(g.name)
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

结合柯里化进行隐式转换: 
代码如下:

package cn.com.toto.gen

/**
  * Created by toto on 2017/7/2.
  */
class Girl(val name : String,var faceValue:Int) {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
package cn.com.toto.gen

import cn.toto.impli.RichFile

/**
  * Created by toto on 2017/7/2.
  */
object MyPreDef {
  implicit object Girl2Ordering extends Ordering[Girl] {
    override def compare(x: Girl, y: Girl): Int = {
      x.faceValue - y.faceValue
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
package cn.com.toto.gen

/**
  * Created by toto on 2017/7/2.
  */
class MissR[T] {

  //如果利用柯里化传入一个隐式转换函数,其作用和Viewbound是一样的,都需要一个隐式转换方法或函数
  def choose(f: T, s: T)(implicit ord: T => Ordered[T]) : T = {
    if (f > s) f else s
  }

  //如果利用柯里化传入一个隐式的类型, 其作用和Contextbound是一样的,都需要一个隐式转换的值
  def select(f: T, s: T)(implicit ord: Ordering[T]) : T = {
    if(ord.gt(f, s)) f else s
  }

  def random(f: T, s: T)(implicit ord: Ordering[T]) : T = {
    import Ordered.orderingToOrdered
    if(f > s) f else s
  }
}

object MissR {
  def main(args : Array[String]): Unit = {
    import MyPreDef._
    val mr = new MissR[Girl]
    val g1 = new Girl("aaa", 80)
    val g2 = new Girl("bbb", 90)
    //val g = mr.choose(g1, g2)
    val g = mr.random(g1, g2)
    //运行结果是:bbb
    println(g.name)
  }
}

猜你喜欢

转载自blog.csdn.net/bbbeoy/article/details/80830600