码迷,mamicode.com
首页 > 其他好文 > 详细

[Scala基础系列 10]Scala泛型、类型边界

时间:2015-08-12 18:48:48      阅读:128      评论:0      收藏:0      [点我收藏+]

标签:

1.泛型和类型边界

1.1.上限(upper bounds)

我们先看一个简单的实例,用于判断两个变量中较大的值,其中两个变量的类型均为Int型

package com.tv189.advanced

/**
 * Created by molyeo on 2015/8/12.
 */

class PairInt(val first: Int, val second: Int) {
  def bigger = {
    if (first.compareTo(second) > 0) first else second
  }
}

object BoundTest {
  def main(args: Array[String]) {
    val pairInt = new PairInt(1, 2)
    println(pairInt.bigger)
  }
}

上述PairInt类中的bigger方法调用了compare方法,如果我们想比较两个String型的变量的大小,我们可以和上面一样,添加PairStr类

class PairStr(val first: String, val second: String) {
  def bigger = {
    if (first.compareTo(second) > 0) first else second
  }
}

如果我们针对每种基本类型都写一个具体的类,则代码量太大,同时也不够简洁,此时我们想到泛型能比较容易解决这个问题。

class Pair[T](val first: T, val second: T) {
  def bigger = {
//    if (first.compareTo(second) > 0) first else second
  }
}

然而与此同时,我们定义的泛型T并指定没有实现compareTo方法,也没有指定为某个类型的子类。在Java泛型里表示某个类型是Test类型的子类型,使用extends关键字:

<T extends Test>

//或用通配符的形式:
<? extends Test>

这种形式也叫upper bounds(上限或上界),同样的意思在Scala中的写法为

[T <: Test]

//或用通配符:
[_ <: Test]

上面的需求采用泛型结合上限,代码如下:

package com.tv189.advanced

/**
 * Created by molyeo on 2015/8/12.
 */

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


object BoundTest {
  def main(args: Array[String]) {
    val pairStr = new Pair[String]("hadoop", "spark")
    println(pairStr.bigger)

    val pairInt = new Pair[Integer](1, 2)
    println(pairInt.bigger)
  }
}

 1.2.下限(lower bounds)

与上限相对应,在Scala中也有lower bounds(下限或下界),即表示某个类型是Test类型的父类型

[T >: Test]

//或用通配符:
[_ >: Test]

下限具体有什么用,主要是用于类型的安全转型,先看下面的代码

class Pair_Lower[T](val first: T, val second: T) {
  def replaceFirst[R >: T](newFirst: R): Pair_Lower[R] = new Pair_Lower[R](newFirst, second)
}

我们创建Pair_Lower的类,其中可以包含两个元素,元素类型为泛型的T。

Pair_Lower类中有一个replaceFirst方法,用来把第二个元素和一个新的元素结合起来组成一个新的Pair_Lower。新的元素的类型是泛型的R。新组成的Pair_Lowe的类型是Pair_Lower[R]。

新的Pair_Lower的类型怎么能是Pair_Lower[R]呢?replaceFirst的签名给我们说明了这一点。[R >: T]。这种标记的含义是说R是T的基类。那么一个T和一个R自然可以组合成一个R的Pair_Lower。接下来我们看一个下限的具体例子

package com.tv189.advanced

/**
 * Created by molyeo on 2015/8/12.
 */

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

class Pair_Lower[T](val first: T, val second: T) {
  def replaceFirst[R >: T](newFirst: R): Pair_Lower[R] = new Pair_Lower[R](newFirst, second)
}
class Vehicle {}

class Car extends Vehicle {}

class Tank extends Vehicle {}


object BoundTest {
  def main(args: Array[String]) {
    val twoCars: Pair_Lower[Car] = new Pair_Lower(new Car(), new Car())
    val tankAndCar: Pair_Lower[Vehicle] = twoCars.replaceFirst(new Tank())
  }
}

首先,我们用两辆汽车组成一个twoCars(Pair_Lower[Car]),然后用一个tank替代原来twoCars中的第一个元素,形成新的Pair_Lower[Vehicle]。

总结一下就是如果newFirst的类型刚好是T的基类,那么R就直接是newFirst的类型。如果newFirst的类型不是T的基类,那R就会是T和newFirst的类型的共同基类。

2.视图边界(View Bounds)

上面上限的代码存在的问题在于对于Int类型的Pair,我们需要指定Pair的类型为[Integer]

val pairInt = new Pair[Integer](1, 2)
println(pairInt.bigger)

否则我们直接用代码

val pairInt = new Pair(1, 2)
println(pairInt.bigger)

则运行的时候会报错

Error:(40, 19) inferred type arguments [Int] do not conform to class Pair‘s type parameter bounds [T <: Comparable[T]]
    val pairInt = new Pair(1, 2)

原因在于Scala类型中的Int类型不属于Comparable[T]边界,然而java中的Integer对象属于Comparable[T]边界。

如果我们不想指定Integer类型,则可以考虑使用Scala的视图边界,写法为

[T <% Test]

代码完善为

//View Bounds
class Pair_Upper_Better[T <% Comparable[T]](val first: T, val second: T) {
  def bigger = {
    if (first.compareTo(second) > 0) first else second
  }
}

我们则可以直接调用如下代码构建Pair_Upper_Better进行比较

val pairStrBetter = new Pair_Upper_Better("hadoop", "spark")
println(pairStrBetter.bigger)

val pairIntBetter = new Pair_Upper_Better(1, 2)
println(pairIntBetter.bigger)

原理是因为在Scala内部发生了隐式转换,将Int类型转换为RichInt类型。

此外如果我们想对String类型的Pair也采用操作符进行比较,则可以采用Ordered[T]来完善代码,具体见Pair_Upper_Perfect类,使代码看起来更加简洁明了。

package com.tv189.advanced

/**
 * Created by molyeo on 2015/8/12.
 */

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

//View Bounds
class Pair_Upper_Better[T <% Comparable[T]](val first: T, val second: T) {
  def bigger = {
    if (first.compareTo(second) > 0) first else second
  }
}

class Pair_Upper_Perfect[T <% Ordered[T]](val first: T, val second: T) {
  def bigger = {
    if (first>second) first else second
  }
}

//class Pair_Lower[T](val first: T, val second: T) {
//  def replaceFirst[R >: T](newFirst: R): Pair_Lower[R] = new Pair_Lower[R](newFirst, second)
//}
//class Vehicle {}
//
//class Car extends Vehicle {}
//
//class Tank extends Vehicle {}


object BoundTest {
  def main(args: Array[String]) {
//    val pairStr = new Pair_Upper[String]("hadoop", "spark")
//    println(pairStr.bigger)
//
//    val pairInt = new Pair_Upper[Integer](1, 2)
//    println(pairInt.bigger)

//    val twoCars: Pair_Lower[Car] = new Pair_Lower(new Car(), new Car())
//    val tankAndCar: Pair_Lower[Vehicle] = twoCars.replaceFirst(new Tank())

//    val pairStrBetter = new Pair_Upper_Better("hadoop", "spark")
//    println(pairStrBetter.bigger)
//
//    val pairIntBetter = new Pair_Upper_Better(1, 2)
//    println(pairIntBetter.bigger)

    val pairStrPerfect = new Pair_Upper_Perfect("hadoop", "spark")
    println(pairStrPerfect.bigger)

    val pairIntPerfect = new Pair_Upper_Perfect(1, 2)
    println(pairIntPerfect.bigger)

  }
}

 

[Scala基础系列 10]Scala泛型、类型边界

标签:

原文地址:http://www.cnblogs.com/molyeo/p/4724721.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!