Scala泛型

这篇具有很好参考价值的文章主要介绍了Scala泛型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

泛型的定义

object _11_泛型 {
  def main(args: Array[String]): Unit = {
    //[A]  这个代表的就是泛型  ==》 在创建对象的时候,可以指定需要传进去的类型
    //作用就是在创建对象的时候,可以对传进去的参数一个约束,当设置泛型位int之后,那么传进去的值就必须是int
    //apply[A](xs: A*): List[A] = xs.toList
    val ints: List[Int] = List[Int](1, 2, 3, 4)

    //自己写一个?  单纯演示泛型语法的定义,没有什么实际的意义
    /**
     * 将泛型定义在类上,那么在整个类中,都可以使用该泛型,作用域是整个类
     * @tparam T
     */
    class TestFanXin[T](){
      def max(a:T,b:T)= a
    }
    //如果设置泛型位Int类型,那么方法的参数就只能传Int类型
    new TestFanXin[Int]().max(1,2)
    //如果设置泛型位String类型,那么方法的参数就只能传String类型
    new TestFanXin[String]().max("aa","bb")

    /**
     * 泛型也可以定义在方法上,如果定义在方法上,那么该泛型的作用域只能作用在该方法中
     * 出了该方法便不能生效
     */
    class TestFanXin1(){
      def max[T](a:T,b:T)= a
      def min[A](a:A,b:A)= b
    }
  }
}

泛型上下限

泛型的上下限的作用是对传入的泛型进行限定。
语法:

//泛型上限  只能够传Person 这个类和他的的子类
Class PersonList[T <: Person]{ 
}
//泛型下限 只能够传Person 这个类和他的的父类
Class PersonList[T >: Person]{ 
}

代码示例:

package com.doit.day02


object _12_泛型的上下限 {
  def main(args: Array[String]): Unit = {

    def sayHi[A <: Father](a:A): Unit ={
      println("test")
    }

    def sayHello[A >: Father](a:A): Unit ={
      println("test")
    }

    //调用sayHi的时候,传进去的参数因为有泛型的上界约定,所以只能传入Father和Father的子类
    sayHi(new Son())
    sayHi(new Father())
    //这边编译的时候虽然不报错,但是运行的时候会报错
//    sayHi(new GrandFather())

    //如果泛型是定义在方法上的,如果没有加泛型,是限制不住的,但是加了泛型,还是可以限制住的
//    sayHello[ABC](new ABC)
//    sayHello[Son](new Son)
    sayHello(new Father)
    sayHello(new GrandFather)


    class Test[A >:Father]{
      def sayHi(a:A) ={
        println("hello")
      }
    }

    new Test[Father].sayHi(new Father)
    //如果定义在类上的话,就能约束住了
//    new Test[Son].sayHi(new Son)
    new Test[GrandFather].sayHi(new GrandFather)




  }
}

class Son extends Father

class Father extends GrandFather

class GrandFather

class ABC

视图限定

约束本质:存在一个隐式转换,能够将T类型转换成B类型
泛型视图限定:T <% B

package com.doit.day02

object _13_视图限定 {
  def main(args: Array[String]): Unit = {

    class Bird(val name:String){
      def fly()={println(name + "飞走了")}
    }

    class ToyBird

    def bitBird[T <% Bird](b:T)=b.fly()

    bitBird[Bird](new Bird("小鸟"))

    implicit def toy2Bird(toyBird: ToyBird)= new Bird("玩具鸟")

    bitBird[ToyBird](new ToyBird)
  }
}

上下文限定

上下文限定是将泛型和隐式转换的结合产物,以下两者功能相同,使用上下文限定[A : Ordering]之后,方法内无法使用隐式参数名调用隐式参数,需要通过 implicitly[Ordering[A]]获取隐式变量,如果此时无法查找到对应类型的隐式变量,会发生出错误。

implicit val x = 1
val y = implicitly[Int]
val z = implicitly[Double]

语法:

def f[A : B](a: A) = println(a) 
//等同于 def f[A](a:A)(implicit arg:B[A])=println(a)```
代码示例:
```Scala
package com.doit.day02

object _14_上下文界定 {
  def main(args: Array[String]): Unit = {

    /**
     * 泛型的上下文界定
     */

    case class Tiger(age:Int,weight:Int)
    case class Cat(age:Int,weight:Int)
    //我想比较两个老虎的大小  单纯的老虎,没有实现compare方法的话,是没有办法调用compare来比较的
    //两个办法,第一个办法,在类上实现Ordered 特质,重写 compareTo方法
    //第二个方法,传一个比较器进去,这样他们就可以用比较器来比较了
    def bigger(tiger: Tiger,tiger1:Tiger,cmp:Ordering[Tiger]):Tiger={
      if (cmp.compare(tiger,tiger1)> 0) tiger else tiger1
    }

    //上面这种方法确实是可以比较,但是只能比较老虎,我想比较个猫好像就比较不了了
    //想比较猫,得重新在写一个
    def bigger1(cat: Cat,cat1:Cat,cmp:Ordering[Cat]):Cat={
      if (cmp.compare(cat,cat1)> 0) cat else cat1
    }

    //不过回头想比较狗狗,又要写一个,比较麻烦,不通用
    //这时候就可以定义泛型了
    def bigger2[T](t: T,t1:T,cmp:Ordering[T]):T={
      if (cmp.compare(t,t1)> 0) t else t1
    }

    //方法的调用  这样是没什么问题的
    //但是在马大爷眼里,这么写代码,多low啊,不符合马大爷的气质,他就开始搞事情了
    bigger2[Cat](Cat(10,100),Cat(20,80),new Ordering[Cat] {
      override def compare(x: Cat, y: Cat) = x.age - y.age
    })

    //咱们不是有隐式转换嘛,能不能把这个比较器呢?
    //我上下文中找找,有没有什么隐式的比较器可以拿过来用,如果有我就直接拿过来,这样就不用传比较器了,去偷一个不香嘛
    //bigger3[T :Ordering]  注意:如果想让他自己偷一个,那么需要实现上下文界定,不然是没办法使用的
    def bigger3[T :Ordering](t: T,t1:T):T={
      if(implicitly[Ordering[T]].compare(t,t1)>0) t else t1
    }

    /**
     * 两种创建隐式比较器对象的写法
     */
    //    implicit val value: Ordering[Cat] = new Ordering[Cat] {
//      override def compare(x: Cat, y: Cat) = x.age - y.age
//    }

    implicit val value1 = Ordering.by[Cat,Int](cat=>cat.age)

    bigger3[Cat](Cat(10,100),Cat(20,80))
  }
}

逆变,协变,不变

语法:
不变:默认
协变: +T
逆变: -T文章来源地址https://www.toymoban.com/news/detail-807403.html

package com.doit.day02

/**
 *
 * 不变:默认
 * 协变: +T
 * 逆变: -T
 */
object _15_逆变协变不变 {
  def main(args: Array[String]): Unit = {

    class Box[T](t:T)
    class Pencil
    class YZPencil extends Pencil

    /**
     * 本身我的pencil 和YZpencil 是父子关系
     * 那么按照常理来说,我装笔的盒子也是圆珠笔的盒子的父类,这样的话咱们能够理解
     * 我盒子既然能装笔,而且圆珠笔又是笔的父类,所以我这个盒子应该能装圆珠笔
     * 毕竟有多态的存在,我的笔本身可以接收圆珠笔的 ==>理解 ?
     */
    val box1: Box[Pencil] = new Box[Pencil](new Pencil)
    val box2: Box[YZPencil] = new Box[YZPencil](new YZPencil)
    //但是在代码中,却不能这么操作  虽然圆珠笔和笔存在父子关系,但是一旦把他们装在盒子中,就不存在这样的关系了
    //这种的关系我们称他为不变
//    val box3: Box[Pencil] = new Box[YZPencil](new YZPencil)  //报错

    //如果想让他们依然有关系,可以的,scala给我提供了另外一种方式叫协变和逆变
    class Box1[+T](t:T)
    class Pencil1
    class YZPencil1 extends Pencil1
    //本身圆珠笔是笔的子类,加上了协变这么一个操作  那么装笔的盒子就是装圆珠笔的父类了
    val box3: Box1[Pencil1] = new Box1[YZPencil1](new YZPencil1)


    // 逆变
    //如果想让他们依然有关系,可以的,scala给我提供了另外一种方式叫协变和逆变
    class Box2[-T](t:T)
    class Pencil2
    class YZPencil2 extends Pencil2
    //本身圆珠笔是笔的子类,加上了逆变这么一个操作  那么装笔的盒子就是装圆珠笔的子类了(父子关系颠倒过来了)
    val box4: Box2[YZPencil2] = new Box2[Pencil2](new Pencil2)

  }
}

到了这里,关于Scala泛型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • hive array[bigint]转string

    label_value 字段类型为 array[bigint] label_value 字段类型为 string 用现有函数array_join ,array转string

    2024年02月11日
    浏览(36)
  • Scala反射调用object

    和反射class不同,反射class和java反射一样,object是静态代码块模式的单例,Scala 反射的核心是 scala.reflect.runtime.universe:代码如下: object:   反射调用: 反射 Scala object 核心是通过 staticModule 获取 ModuleMirror:

    2024年02月11日
    浏览(36)
  • JavaScript 数组Array存储方式及对象Object

    一、数组的存储 1、当声明一个变量时,var a = 111; 在后台计算机翻译时,var声明 a变量 所以此时会产生一个栈内存,变量 a 的初始值为undefined,然后 = 111 ; undefined消失,111的值被赋值给了a。如果多个变量赋值的话,栈内存的执行顺序是先进后出的顺序。也叫做压栈。栈内存

    2024年02月08日
    浏览(47)
  • nlohmann json:通过items遍历object/array

    编译运行输出: key: one, value: 1 key: two, value: 2 key: 0, value: 1 key: 1, value: 2 key: 2, value: 4 key: 3, value: 8 key: 4, value: 16  可以看到对于object可以通过key()和value()拿到键值对 对

    2024年02月13日
    浏览(46)
  • 【C++ STL之string,tuple,array详解】

    在C++的STL(Standard Template Library)中,std::string是一个非常有用的字符串类。它提供了一系列操作字符串的功能,包括字符串的创建、修改、查找、拼接等。本文将详细介绍C++ STL中std::string的使用方法和一些常见操作。 (1) 支持比较运算符 string字符串支持常见的比较操作符(

    2024年02月12日
    浏览(50)
  • java 字符串转数组(String to Array)

    java 字符串转数组(String to Array) 数组转List、 判断String数组中是否包含某个字符串

    2024年02月12日
    浏览(50)
  • 创建scala项目并增加新的object试运行

    依赖配置: scala,jdk,maven 没有maven也可以创建 1.1.1 创建 选择新project 路径、依赖配置、代码调试 1.1.2 项目结构 Scala项目中几个文件: .idea:这个文件夹是用来存储项目的配置信息的,包括项目的结构、依赖库等。它是由IntelliJ IDEA自动生成的,并且通常不需要手动修改。

    2024年02月07日
    浏览(34)
  • 泛型中K TVE? Object等分别代表什么含义。

    E一Element(在集合中使用,因为集合中存放的是元素) T- Type (Java类) K - Key(键)  V- Value (值) N- Number(数值类型) ?-表示不确定的java类型(无限制通配符类型) S、U、V- 2nd、3rd、4th types Object-是所有类的根类,任何类的对象都可以设置给该Object引用变量,使用的时候可能需要类型强制转

    2024年02月12日
    浏览(44)
  • Java中泛型和Object类型 初级进阶教程(一)

    在学习的过程中,常常看到某个类或者接口等中使用 ListT, TestT,其中T的作用是什么呢? 1 在类中使用泛型 2 使用多个泛型 3 在类中使用泛型 4 在方法中使用泛型 5 限制泛型类型 6 通配符 (Wildcard) 总结:泛型和Object类型之间的区别 类型安全: 泛型 T : 泛型提供了编译时类型

    2024年02月01日
    浏览(54)
  • JSON转换List<Map<String, Object>>、Map<String, Object>

    废话就不说了 早上10点研究到现在 获取redis的JSON字符串 String getPalletListNew = redisService.getRedis(“getPalletListNew”, abroad + “” + goodsLevel + “” + startPort + “” + destinationPort + “” + maxTon + “” + minTon); 转换MapString,Object public MapString, Object jsonToMap(String json){ MapString, Object map = new

    2024年02月20日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包