五.cala语言的高级特性

1.什么是泛型类

和Java或者C++一样,类和特质可以带类型参数。在Scala中,使用方括号来定义类型参数

/**

* 需求:定义一个类,来操作整数

*/

class GenericClassInt {

private var content:Int = 10

def set(value:Int) = {content = value}

def get() :Int = {content}

}

/**

* 需求:定义一个类,来操作字符串

*/

class GenericClassString {

private var content:String = ""

def set(value:String) = {content = value}

def get() :String = {content}

}

/**

* 问题:能不能定义一个类,既可以操作整数,也可以操作字符串

*

* 解决:定义泛型类

*/

class GenericClass[T] {

private var content:T = _ // 初始值用 _ 表示

def set(value:T) = {content = value}

def get() :T = {content}

}

object GenericClass {

def main(args: Array[String]): Unit = {

var v1 = new GenericClass[Int] // 相当于 GenericClassInt

v1.set(10000)

println(v1.get())

var v2 = new GenericClass[String]

v2.set("Hello")

println(v2.get())

}

}

2.什么是泛型函数

函数和方法也可以带类型参数。和泛型类一样,我们需要把类型参数放在方法名之后。

注意:这里的ClassTag是必须的,表示运行时的一些信息,比如类型。

scala> def mkIntArray(elem:Int*) = Array[Int](elem:_*)

mkIntArray: (elem: Int*)Array[Int]

scala> mkIntArray(1,2,3)

res25: Array[Int] = Array(1, 2, 3)

scala> mkIntArray(1,2,3,4,5,6)

res26: Array[Int] = Array(1, 2, 3, 4, 5, 6)

scala> def mkArray[T:ClassTag](elem:T*) = Array[T](elem:_*)

:11: error: not found: type ClassTag

def mkArray[T:ClassTag](elem:T*) = Array[T](elem:_*)

^

:11: error: No ClassTag available for T

def mkArray[T:ClassTag](elem:T*) = Array[T](elem:_*)

^

scala> import scala.reflect.ClassTag

import scala.reflect.ClassTag

scala> def mkArray[T:ClassTag](elem:T*) = Array[T](elem:_*)

mkArray: [T](elem: T*)(implicit evidence$1:

scala.reflect.ClassTag[T])Array[T]

scala> mkArray(1,2,3)

res27: Array[Int] = Array(1, 2, 3)

scala> mkArray("123","456")

res28: Array[String] = Array(123, 456)

3.Upper Bounds 与 Lower Bounds

类型的上界和下界,是用来定义类型变量的范围。它们的含义如下:

S <: T

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

U >: T

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

scala> def addTwoString[T <: String](x:T,y:T) = x + " *** " + y

addTwoString: [T <: String](x: T, y: T)String

scala> addTwoString("123","456")

res29: String = 123 *** 456

scala> addTwoString(1,2)

:14: error: inferred type arguments [Int] do not conform to method

addTwoString's type parameter bounds [T <: String]

addTwoString(1,2)

^

:14: error: type mismatch;

found : Int(1)

required: T

addTwoString(1,2)

^

:14: error: type mismatch;

found : Int(2)

required: T

addTwoString(1,2)

^

scala> addTwoString(1.toString,2.toString)

res31: String = 1 *** 2

4.视图界定(View bounds)

它比 <: 适用的范围更广,除了所有的子类型,还允许隐式转换过去的类型。用 <% 表示。尽量使用视图界定,来取代泛型的上界,因为适用的范围更加广泛。

scala> def addTwoString[T <% String](x:T,y:T) = x + " *** " + y

addTwoString: [T](x: T, y: T)(implicit evidence$1: T => String)String

scala> addTwoString(1,2)

:14: error: No implicit view available from Int => String.

addTwoString(1,2)

^

scala> implicit def int2String123123(n:Int):String = n.toString

warning: there was one feature warning; re-run with -feature for details

int2String123123: (n: Int)String

scala> addTwoString(1,2)

res34: String = 1 *** 2

//主意:不要多次定义相同功能的隐式函数

scala> implicit def int2String12sdfdf3123(n:Int):String = n.toString

warning: there was one feature warning; re-run with -feature for details

int2String12sdfdf3123: (n: Int)String

scala> addTwoString(1,2)

:16: error: ambiguous implicit values:

both method int2String123123 of type (n: Int)String

and method int2String12sdfdf3123 of type (n: Int)String

match expected type Int => String

addTwoString(1,2)

5.协变和逆变

协变:

Scala的类或特征的范型定义中,如果在类型参数前面加入+符号,就可以使类或特征变为协变了。

/**

* 协变

* */

//动物类,父类

class Animal {}

//鸟类,动物类的子类

class Brid extends Animal{}

//吃的类

class Eat[+T](t:T){

}

/**

* 测试

* */

object Test{

def main(args: Array[String]): Unit = {

//创建鸟吃东西的对象

var brid:Eat[Brid] = new Eat[Brid](new Brid)

//创建一个动物吃东西的对象

//问题是,能否将鸟吃东西的对象赋值个动物吃东西的对象

//原因是:Brid是Animal的子类,但是Eat[Brid]不是Eat[Animal]的子类

var animal:Eat[Animal] = brid

}

}

逆变:

在类或特征的定义中,在类型参数之前加上一个-符号,就可定义逆变范型类和特征了。

/**

* 逆变

* */

//动物类,父类

class Animal {}

//鸟类,动物类的子类

class Brid extends Animal{}

//鹦鹉,鸟的子类

class Parrot extends Brid{}

//吃的类

class Eat[-T](t:T){

}

/**

* 测试

* */

object Test{

def main(args: Array[String]): Unit = {

//创建鸟吃东西的对象

var brid:Eat[Brid] = new Eat[Brid](new Brid)

//创建一个鹦鹉吃东西的对象

//问题是,能否将鸟吃东西的对象赋值个鹦鹉吃东西的对象

//原因是:Brid是Parrot的父类,但是Eat[Brid]不是Eat[Parrot]的父类

var animal:Eat[Parrot] = brid

}

}

总结:Scala的协变:泛型变量的值可以是本身类型或者其子类的类型

Scala的逆变:泛型变量的值可以是本身类型或者其父类的类型

6.隐式转换函数

所谓隐式转换函数指的是以implicit关键字申明的带有单个参数的函数。

/**

* 隐式函数

* */

//猴子类

class Monkey(f:Fruit) {

def eat(): Unit ={

println("猴子吃"+f.getFruitName)

}

}

//水果类

class Fruit(name:String){

def getFruitName: String ={

name

}

}

/**

* 测试

* 需求:猴子吃香蕉

* */

object Test{

def main(args: Array[String]): Unit = {

//正常调用

var monkey = new Monkey(new Fruit("香蕉"))

monkey.eat()

//问题:能不能定义香蕉类的时候直接调用吃的方法

//定义隐式函数

val f:Fruit = new Fruit("香蕉")

f.eat()

}

implicit def fruitToMonkey(f:Fruit): Monkey ={

new Monkey(f)

}

}

7.隐式参数

使用implicit申明的函数参数叫做隐式参数。我们也可以使用隐式参数实现隐式的转换

/**

* 隐式参数

* */

object Demo1 {

/**

* 定义一个有参数的方法

* 问题是:如何在调用方法的时候不传递参数

* */

implicit var n = "张三"

def ss(implicit name:String): Unit ={

println("我的名字是:"+name)

}

def main(args: Array[String]): Unit = {

ss

}

}

/**

*定义一个方法可以进行任意类型数据的比较

*/

def smaller[T](x:T,y:T)(implicit order:T => Ordered[T]): T ={

if(x > y) x else y

}

8.隐式类

所谓隐式类: 就是对类增加implicit 限定的类,其作用主要是对类的功能加强!

/**

* 隐式类

* 需求,通过n.add(m)实现n+m的值,也就是实现两个数的和

* */

object Demo2 {

//定义隐式类

implicit class ADD1(x:Int){

def add(a:Int) = a+x

}

def main(args: Array[String]): Unit = {

println(5.add(10))

}

}

你可能感兴趣的:(五.cala语言的高级特性)