微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

scala类型参数05

所谓类型参数,其实就是java中的泛型。

scala中的泛型和java中的泛型高度相似,也可以定义在类,方法上,成员变量上的泛型也需要沿用类的声明,定义的是一般也是用一个大写字母,但是泛型定义时需要使用[]包裹。

1. 泛型类

class XxxDao[T] {
	def insert(t: T): Unit = {
	}
}
trait XxxService[T] {
	def save(t: T): Unit
}
class XxxServiceImpl extends XxxService[User] {
	val dao = new XxxDao[User]()
	override def save(t: User): Unit = {
		dao.insert(t)
	}
}
class XxxController {
	val service = new XxxServiceImpl
	def register(t: User): Unit = {
		service.save(t)
	}
}
class User(name:String, age:Int) {
}

2.泛型上限,视图界定

//scala版本的方法泛型

object _02Genericops {
    def main(args: Array[String]): Unit = {
        val arr = Array[Integer](3, -1, 0, 5, -5, 7, 6)
        println("排序前的数组:" + arr.mkString("[", ", ", "]"))
        insertSort(arr)
        println("排序后的数组:" + arr.mkString("[", ", ", "]"))
    }

    /*
        scala中的泛型的限定语法格式
            T <: 类型
        java中的泛型限定语法格式
            T extends 类型
     */
    def insertSort[T <: Comparable[T]](array: Array[T]): Unit = {
        for(x <- 1 until array.length) {
            for(y <- 1 to x reverse) {
                if(array(y).compareto(array(y - 1)) < 0) {
                    swap(array, y, y - 1)
                }
            }
        }
    }

    private def swap[T](arr: Array[T], y: Int, x: Int): Unit = {
        val temp = arr(y)
        arr(y) = arr(x)
        arr(x) = temp
    }
}

我们将java的版本修正为scala的版本,传入Integer类型的数组,完美解决问题,但是如果传递的是一个Int类型的数组,编译就会报错:

这个错误说的是Int类型,不具备比较性

确实没有体现出Comparable的特性,所以是不能直接进行比较,但是Int类型的数据,在scala中确确实实可以进行加减乘除等等运算,比较也是可以的,所以我们想要让上述代码也能执行成功,就需要将泛型定义的修改为:
[T <: Comparable[T]] ==> [T <%: Comparable[T]]

3.泛型的协变和逆变

当然认情况下,scala也只能支持=左右两侧泛型是一致的,但是为了程序更加的灵活和通用,scala也支持泛型出现继承关系,所谓协变和逆变。

object _03Genericops {
    def main(args: Array[String]): Unit = {
        val myList1:MyList[Person] = new MyList[Person]()
        val myList2:MyList[Person] = new MyList[Student]()//泛型的协变
        
        val myList3:MyList1[Student] = new MyList1[Person]()//泛型的逆变
    }
}

class MyList[+T] {//泛型协变的定义
}
class MyList1[-T] {//泛型逆变的定义
}

class Person {}
class Student extends Person{}

4. 隐式转换

scala提供的能够将一种类型根据需要,自动转化成其他类型的操作方式,进而可以让原有的类型具备其没有的功能,丰富现有api,而不会对原有的代码造成过多的污染。

​ 这一点是scala程序非常优秀的一点设计,是java等其它语言所不具备的能力。其实在前面的视图界定案例中,视图界定就采用的是隐式转换将Int类型转化成为了RichInt,而RichInt扩展了Comparable接口,自然可以进行比较了。

在这里插入图片描述

这样,变量source就会在自己的作用域范围内自动搜索是否有这样的隐式转换,如果有,则自动完成类型转换或者加强。
通过隐式转换函数实现

implicit def double2Int(d:Double):Int = d.toInt
val a:Int = 3.5
println("a=" + a)

5.利用隐士转换丰富现有类库的功能

利用隐士转换丰富现有类库的功能,举例说明,通过java.io.File来读取一个文件中的内容,但是File没有read的功能,如何能做到让File也具备流的读写功能

def main(args: Array[String]): Unit = {
    val file = new File("E:/data/hello.txt")
    file.read().foreach(println)
}

implicit def file2RichFile(file:File):RichFile = new RichFile(file)
//将file最后要转化为RichFile,才能具备read的功能
class RichFile(file:File) {
    def read() = Source.fromFile(file).getLines()
}

6.引入隐士转换

当开发出一个隐式转换函数时,该如何使用呢?

最简单的其实就是,只要在要转换的变量的作用域内能够访问的到,即可进行自动转换,不需要人工干预。

​ 在同一个文件中定义的隐式转换,不需要做任何的干预,但是如果要导入其它类中定义的隐式转换,要想在本类中使用,就必须要像导包一样导入。只要在其作用域到导入,即可。同时这个导入的隐式转换因为和导包一样,也不存在对原有类的结构发生入侵。

我们在导入的时候,我们倾向于导入到最靠近变量的部分。越靠近变量,其作用域范围越小,影响越小。

object _03ImplicitOps {
    def main(args: Array[String]): Unit = {
        import _02ImplicitOps._
        val file = new File("E:/data/hello.txt")
        file.read().foreach(println)
    }
}

7.隐式转换参数

一个函数的参数被implicit修饰,称该参数为隐式转换参数,这个隐式转换参数在传递的时候,可以传,有时候也可以不用传。

def main(args: Array[String]): Unit = {
    val list = List(3, -3, 0, -8, 45, 4)

    list.foreach(println)
    println("---------------")
    implicit val ord = new Ordering[Int](){
        override def compare(x: Int, y: Int) = {
            y.compareto(x)
        }
    }
    //显示的传递隐式转换参数
    list.sorted(ord).foreach(println)
    println("-------隐式传递---------")
    //隐式传递隐式转换参数
    list.sorted.foreach(println)
}

说明:隐式转换参数,可以显示的指定,也可以隐式的指定,如果是隐式指定,就需要让该变量在其作用域内访问到被implicit关键字修饰的相关变量,自动进行赋值。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐