美文网首页
scala 类型参数、界定、类型约束

scala 类型参数、界定、类型约束

作者: scandly | 来源:发表于2018-08-16 13:19 被阅读0次

    类、特质、方法和函数都可以有类型参数

    将类型参数放置在名称之后,以方括号括起来

    参数类型(不能什么都传,要加限定)

    对于参数类型的 class 实际类型会在new对象时推断

    例如:class Pair[T, S](val first: T, val second: S)

    val p = new Pair(42, "String")

    参数类型界定

    1、<: 和 >: (我定义为 “纯子类界定”)

    class Pair[T](val first: T, val second: T)

    它要求 两个参数类型相同

    添加一个方法,返回较小的那个值:

      class Pair[T](val first: T, val second: T) {

        def smaller = if (first.compareTo(second) < 0) first else second

      }

    这是错的,因为我们并不知道first是否有compareTo方法,所以添加一个上界T<:Comparable[T]  (必须是以可比较的类型)

      class Pair[T <: Comparable[T]](val first: T, val second: T) {

        def smaller = if (first.compareTo(second) < 0) first else second

      }

    原来给T什么都可以传,现在就不行了。

    你也可以为类型指定一个下界(也就是要求是子类)。

    举例,把第一个组件替换为子类。

      class Person  class Student extends Person

      class Pair[T](val first: T, val second: T) {

        def replaceFirst(newFirst: T) = new Pair[T](newFirst, second)

      }

    假定我们有一个Pair[Person],我们想用Student 替换第一个类型,实际上这样是不可行的,因为T必须一致。因此,在函数后面定义下界。

      class Pair[T](val first: T, val second: T) {

        def replaceFirst[R >: T](newFirst: R) = new Pair[R](newFirst, second)

      }

    2、<% 视图界定 (我定义为:“含隐式条件的子类界定”)

    前面有一个带上界的示例:

    把 前面的例子 class Pair[T <: Comparable[T]]

    如果你new一个Pair(4,2),编译器会报错,Scala的Int类型并没有实现Comparable。

    解决办法是使用视图界定:

      class Pair[T <% Comparable[T]](val first: T, val second: T) {

        def smaller = if (first.compareTo(second) < 0) first else second

      }

    <% 意味着 T 可以被隐式转换成Comparable[Int]。

    隐式类型转换,Int 转 RichInt ,RichInt实现了Comparable[Int]

    3、T:M 上下文界定 (我定义为:“含隐式的子类界定”)

    其中M是另一个泛型类。它要求必须存在一个类型为M[T]的“隐式值”。也就是说必须把这个类型放在另外一个类型里

      class Pair[T : Ordering](val first: T, val second: T) {

        def smaller(implicit ord: Ordering[T]) =

          if (ord.compare(first, second) < 0) first else second

      }

    4、<% 上Manifest 上下文界定

    Manifest were added specially to handle arrays

    要实例化一个泛型的Array[T],我们需要一个Manifest[T]对象。要想让基本类型的数组能够正常工作的话,这是必须的。举例来说,如果T是Int,你会希望虚拟机中对应的是一个int[]数组。在Scala中,Array只不过是类库提供的一个类,编译器并不对它做特殊处理。如果你要编写一个泛型函数来构造泛型数组的话,你需要传入这个Manifest对象来帮忙。由于它是构造器的隐式参数,你可以用上下文界定:

      def makePair[T: Manifest](first: T, second: T) = {

        val r = new Array[T](2)

        r(0) = first

        r(1) = second

      }

    类型约束

    类型约束提供的是另一个限定类型的方式。总共有三种关系可供使用:

    T=:=U 测试T是否等于U

    T<:

    T<%

    要使用这样一个约束,需要添加“隐式类型证明参数”:

    class Pair[T](val first: T, val second: T)(implicit ev: T <:< Comparable[T])

    不过在上面的例子中,使用类型约束并没有比类型变量界定class Pair[T<:Comparable[T]]有更多的优点。不过在某些场景下,类型约束会很有用。

    类型约束让你可以在泛型类中定义只能在特定条件下使用的方法,示例如下:

      class Pair[T](val first: T, val second: T) {

        def smaller(implicit ev: T <:< Comparable[T]) =

          if (first.compareTo(second) < 0) first else second

      }

      val p1 = new Pair("a", "b") //a

    你可以构造出Pair[File],尽管File并不是带有先后次序的。只有当你调用smaller方法的时候才会报错。

    型变:协变和逆变

    class Personclass Student extends Person

    def makeFriends(p: Pair[Person]) //此函数要对Pair[Person]做某种处理,但是要调用Student里的方法

    我们知道,因为虽然Student是Person的子类,但是Pair[Student]和Pair[Person]一点关系都没有。如果你想要这样的关系,则必须在定义Pair类的时候表明这一点:

    class Pair[+T](val first: T, val second: T)// 可以协变,表明,可以用子类的方法

    +号意味着如果Student是Person的子类,那么Pair[Student]也是Pair[Person]的子类。

    也可以有另一个方向的型变。考虑泛型类型Friend[T],表示希望与类型T的人成为朋友的人:

      trait Friend[-T] {

        def befriend(someone: T)

      }

    现在假定有一个函数:

      def makeFriendWith(s: Student, f: Friend[Student]) {

        f.befriend(s)

      }

    你能用Friend[Person]作为参数调用它吗?也就是说,如果你有:

      class Person extends Friend[Person]

      class Student extends Person  val susan = new Student  val fred = new Person

    函数调用makeFriendWith(susan,fred)能成功吗?看上去应该可以,因为fred想和任何人叫交朋友,他也一定会和susan交朋友。注意到这个时候,类型变化的方向和子类型方向是相反的。Student是Person的子类,但是Friend[Student]是Friend[Person]的超类。这种情况下,需要将类型参数声明为逆变的。

    协变、逆变,特质的定义会使用到它

    trait Function1 [-T1, +R] extends AnyRef

    相关文章

      网友评论

          本文标题:scala 类型参数、界定、类型约束

          本文链接:https://www.haomeiwen.com/subject/jynnbftx.html