scala 上界 <:, 下界>:, 视界 <%, 边界 :, 协变 +T, 逆变

编程入门 行业动态 更新时间:2024-10-27 20:31:07

scala <a href=https://www.elefans.com/category/jswz/34/1650810.html style=上界 <:, 下界>:, 视界 <%, 边界 :, 协变 +T, 逆变"/>

scala 上界 <:, 下界>:, 视界 <%, 边界 :, 协变 +T, 逆变

概述

上界 (<:) 下界(>:) 是类型约束范畴,用来约束对象的子类是谁,父类是谁
协变 (+T) 逆变(-T)是泛型范畴,主要用于集合类型变量赋值。
视界 (<%) 边界( :)是隐式调用的简写。

上界 (<:) 下界(>:)

上界:要求对象必须是某一个对象的子类,因为子类会继承父类的属性和方法,所以父类的方法和属性这路都可以用。

  trait A {def func()}class B extends A {override def func(): Unit = {println("i am b")}}class C extends A {override def func(): Unit = {println("i am c")}}def test[T <: A](obj: T): Unit = {obj.func()}test(new B()) //  i am btest(new C()) //  i am c

下界:要求对象必须是某一个对象的父类。主要用在已知某一个具体类型,但是要给它赋值给另一个变量,该变量必须是具体类型的父类型才行。

举例:
对于下面的例子,我们要把元素B放到一个集合中,这个集合必须是类型B父类容器才行。这里就是B是已知类型,集合类型未知。

  trait A {def func()}class B extends A {override def func(): Unit = {println("i am b")}}def add[T >: B](list: collection.mutable.Set[T], elem: B): collection.mutable.Set[T] = {list.add(elem)list}

协变 (+T) 逆变(-T)

逆变协变指的是类型T和包装类型直接的关系。
有两个类如下所示:

  trait A {def func()}class B extends A {override def func(): Unit = {println("i am b")}}

假设有个包装类型F[T]

 class F[T]

现在我们生产一个F[B]实例,然后赋值给F[A]类型的变量.就会报错。因为F[B]并不是F[A]的子类。

 val a:F[A] = new F[B]() // error

所以这个时候才会需要逆变和协变。
协变:子类的包装类型也是父类包装类型的子类

  class F[+T] // 协变val a: F[A] = new F[B]() // 正确

逆变:子类的包装类型是父类包装类型的父类

  class G[-T] // 逆变val b: G[B] = new G[A]() // 正确

一个比较经典的例子是:scala 函数的定义.scala中所有的函数,参数都是逆变的,返回值都是协变的。 trait Function[-T1,+T2].也就是说一个函数要赋值给一个函数类型变量。这个函数的参数必须是函数变量参数的父类,返回值必须是函数变量返回值的子类。

    trait A {def func()}class B extends A {override def func(): Unit = {println("i am b")}}class C extends B {}val func: B => B = (a: A) => { new C() } // 把 A=>C类型的函数赋值给B=>B类型的变量

视界 <%, 边界 :

视图和边界看到的比较多,但是功能比较强大,也容易被误解。比如 ( : )就经常会被误以为是上界和下届的一种。

视界 <%

视界只是一种隐式类型函数的简写。如果我们需要一个Fruits类型的隐式参数,但是我们只有一个 T 类型,这时就可以用视界。他要求想使用这个函数,必须提供一个由T => Fruits的隐式调用。 比如下面:


scala> case class Fruits(name: String)
defined class Fruitsscala> def getFruits[T <% Fruits](value: T): Fruits = value
getFruits: [T](value: T)(implicit evidence$1: T => Fruits)Fruits等价于scala> def getFruits[T](value: T)(implicit evidence: T => Fruits): Fruits = evidence(value)
getFruits: [T](value: T)(implicit evidence: T => Fruits)Fruits

边界 :

边界相对来将应用场景比较多一些。下面有个函数anothr,需要一个隐式参数。我们在func中调用了这个方法,但是我们并没有提供隐式参数。这就和视图有点类似了。在视图中要求传入一个隐式函数,但这里是要求传入一个隐式类型。

class F[T]def another[T](elem: T)(implicit f: F[T]) = {// do nothing
}def func[T: F](elem: T): Unit = {another(elem)
}scala>  def func[T: F](elem: T): Unit = {another(elem)}func: [T](elem: T)(implicit evidence$1: F[T])Unit
// 使用
scala> func(1)(new F[Int]())
或则
scala> func(1)(new F()) //自行推断

有一个比较经典的例子,利用这个方法可以实现隐式泛型

import scala.reflect.runtime.universe._typeOf函数需要传入一个隐式类型TypeTag[T]
// def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpedef getTypeTag[T: TypeTag](obj: T) = typeOf[T] // 我们调用的时候也没有传入隐式类型,因为scala运行环境中会自定存储。
getTypeTag(1)

更多推荐

scala 上界 <:, 下界>:, 视界 <%, 边界 :, 协变 +T, 逆变

本文发布于:2023-07-03 16:27:05,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1008936.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:上界   下界   边界   视界   逆变

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!