Kotlin泛型<in, out, where>概念及示例

news2024/12/29 9:16:45

Kotlin泛型<in, out, where>概念及示例

在 Kotlin 中,泛型用于指定类、接口或方法可以操作的对象类型。
在这里插入图片描述
不变

in

in关键字用于指定泛型类型是“输入”类型,这意味着它将仅用作函数或类的参数。

interface ReadOnly {
    fun read(): Any
}

class ReadWrite<in T>(private var value: T) : ReadOnly {
    override fun read(): Any = value

    // 'in' keyword allows to use T as an input only
    // so, the following line will give a compile error
    // fun write(value: T) { this.value = value }
}

另外一个例子:

interface Consumer<in T> {
    fun consume(item: T)
}

class StringConsumer : Consumer<String> {
    override fun consume(item: String) {
        println("Consuming string: $item")
    }
}

class AnyConsumer : Consumer<Any> {
    override fun consume(item: Any) {
        println("Consuming any type: $item")
    }
}

fun main() {
    val stringConsumer = StringConsumer()
    stringConsumer.consume("Hello") // prints "Consuming string: Hello"

    val anyConsumer: Consumer<Any> = AnyConsumer()
    anyConsumer.consume("Hello") // prints "Consuming any type: Hello"
    anyConsumer.consume(123) // prints "Consuming any type: 123"
}

在上面的例子中,Consumer是一个接口,只有一个方法 consume 接受一个T类型的参数。类型参数T使用in关键字声明,表明它仅用作输入类型。StringConsumerAnyConsumer是两个实现了Consumer接口的类,都可以用来消费各自类型的实例。

out

协变

out 关键字用于指定泛型类型是“输出”类型,这意味着它将仅用作函数或类的返回类型。

interface WriteOnly {
    fun write(value: Any)
}

class ReadWrite<out T>(private var value: T) : WriteOnly {
    // 'out' keyword allows to use T as an output only
    // so, the following line will give a compile error
    // fun read(): T = value

    override fun write(value: Any) {
        // this.value = value  
    }
}

另一个例子:

interface Producer<out T> {
    fun produce(): T
}

class StringProducer : Producer<String> {
    override fun produce(): String = "Hello"
}

class AnyProducer : Producer<Any> {
    override fun produce(): Any = "Hello"
}

fun main() {
    val stringProducer = StringProducer()
    println(stringProducer.produce()) // prints "Hello"

    val anyProducer: Producer<Any> = AnyProducer()
    println(anyProducer.produce()) // prints "Hello"
}

在上面的例子中,Producer是一个接口,它有一个单一的方法 produce,它返回一个T类型的值。类型参数T使用out关键字声明,表明它仅用作输出类型。StringProducerAnyProducer是两个实现了Producer接口的类,都可以用来生成各自类型的实例。

where

where关键字用于指定对可用作参数或返回类型的类型的约束。

interface Processor<T> where T : CharSequence, T : Comparable<T> {
    fun process(value: T): Int
}

class StringProcessor : Processor<String> {
    override fun process(value: String): Int = value.length
}

另外一个例子:

interface Processor<T> where T : CharSequence, T : Comparable<T> {
    fun process(value: T): Int
}

class StringProcessor : Processor<String> {
    override fun process(value: String): Int = value.length
}

fun main() {
    val stringProcessor = StringProcessor()
    println(stringProcessor.process("Hello")) // prints "5"
}

在上面的例子中,Processor是一个接口,只有一个方法process接受一个T类型的参数并返回一个Int。类型参数T使用where关键字声明,并指定两个约束:T必须实现CharSequence接口,并且它必须与自身可比较。StringProcessor是一个实现String类型的Processor接口的类,它可以用来处理String值。

考虑下面类:

class Box<T>(val item: T)

此类定义了一个通用类型T,可用于指定存储在Box中的项目的类型。在没有任何额外约束的情况下,此类可用于创建任何类型的Box:

val intBox = Box(1)
val stringBox = Box("hello")

现在考虑下面的类:

class InOut<in T, out R>(val item: T) {
    fun get(): R {
        return item as R
    }
}

这里,T被定义为“输入”类型(使用in关键字),R被定义为“输出”类型(使用out关键字)。这意味着T只能用作函数的参数,而R只能用作返回类型。这将允许我们定义一个接受InOut类型并返回内部项目的函数:

fun test(input: InOut<String, Any>): Any {
    return input.get()
}

最后考虑下面的类:

class MyClass<T> where T : Number, T : Comparable<T> {
    fun compare(item1: T, item2: T): Int {
        return item1.compareTo(item2)
    }
}

在这里,T被定义为泛型类型,仅限于同时是NumberComparable<T>的类型。这意味着只能使用类型为NumberComparable<T>的参数调用比较函数。

val myClass = MyClass<Int>()
val result = myClass.compare(1,2)

在这个例子中,我们可以看到该类只接受Int 类型,因为它是一个Number并且是可比较的。

通过使用in和out,Kotlin提供了对声明点变型的支持,这使我们能够在声明点定义泛型类型的子类型关系,而不是在使用点定义。这使我们能够更安全、更简洁地使用更多的泛型类型,并防止某些可能出现的类型错误。

结论

协变关系

以下是在Kotlin中使用in和out能够实现的一些功能,如果没有它们,这些功能将会很困难或不可能实现:

  1. 定义协变和逆变的泛型类型:out允许我们定义协变的泛型类型,这意味着子类型关系得到保留(例如,List<Child>List<Parent>的子类型)。另一方面,in允许我们定义逆变的泛型类型,这意味着子类型关系的方向被颠倒(例如,Comparator<Parent>Comparator<Child>的子类型)。
  2. 在函数参数和返回类型中使用泛型类型:使用in和out允许我们在函数参数和返回类型中使用泛型类型,以保留子类型关系。例如,我们可以定义一个以List<out Parent>作为参数的函数,这意味着它可以接受List<Child>List<Parent>,但不能接受List<Grandparent>。类似地,我们可以定义一个返回Comparator<in Child>的函数,这意味着它可以返回Comparator<Child>Comparator<Parent>,但不能返回Comparator<Grandparent>
  3. 避免强制转换和类型检查:使用in和out可以在某些情况下避免强制转换和类型检查,因为编译器可以推断不同泛型类型之间的子类型关系。例如,如果我们有一个List<out Any>,我们可以安全地将列表的元素访问为Any,因为我们知道列表的所有元素至少是Any类型的。

总之,in和out是Kotlin中强大的工具,没有它们,我们将不得不使用强制转换、类型检查和其他解决方案来实现相同水平的表达能力和安全性。

参考

【Kotlin泛型】http://www.enmalvi.com/2021/01/31/kotlin-28/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/559983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式期末复习随笔

1.以下是23种GOF设计模式对应的设计原则&#xff1a; 工厂方法模式&#xff08;Factory Method Pattern&#xff09;&#xff1a;遵循开闭原则&#xff0c;客户端不需要修改就能够新增产品类型。 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff1a;遵…

【严重】Kibana 8.7.0 任意代码执行漏洞

漏洞描述 Kibana是用于Elasticsearch的数据可视化仪表板。Kibana在8.7.0版本引入了Synthetic监控功能&#xff0c;用户可配置编写playwright中的javascript代码实现web应用监控。 具备Kibana登录权限的攻击者可利用此功能编写恶意playwright脚本&#xff0c; 从而在Kibana主机…

5.28 深圳活动|Jina AI 生态助力云原生场景下的 AIGC 应用开发

亚马逊云科技 Community Day 将于 5 月 28 日 在深圳南山区海德酒店 11 楼举办&#xff0c;Jina AI 软件工程师付杰将带来 《Jina AI 生态助力云原生场景下的 AIGC 应用开发》 的主题演讲。 Community Day 是亚马逊云科技全球品牌和社区旗舰活动&#xff0c;由社区领导者发起&a…

5个替代Zendesk的全面指南!

Zendesk是一种广受欢迎的客户支持软件解决方案&#xff0c;适用于各种规模的企业。然而&#xff0c;还有其他几种产品可以取代Zendesk&#xff0c;提供类似甚至更好的功能。在本文中&#xff0c;我们将探索市场上一些最好的Zendesk替代方案。 1、Zoho Desk Zoho Desk是一款基…

SpringBoot拦截器-解决java.io.IOException: Stream closed问题

1.SpringBoot拦截器是什么 SpringBoot拦截器和过滤器是Spring Boot的一种机制&#xff0c;用于对请求和响应进行操作的拦截&#xff0c;是AOP编程的一种体现。该方法可以在不改变代码基本业务和逻辑的前提下对SpringBoot的一些操作进行拦截、过滤和更改。 SpirngBoot拦截器&a…

检错纠错理论——海明码与海明距离

概念解释 先说明几个概念&#xff08;非严谨定义&#xff09; 码字&#xff1a;一个包含了数据位和校验位的n位单元&#xff0c;也就是“一种”编码 编码&#xff1a;由码字组成的可以表达传递信息的集合&#xff0c;这里不是指编码的过程&#xff0c;而是一个名词。一个编码…

Unity 环境雾与其它设置

开启雾 window->Rendering->Lighting->Environment Fog Color&#xff1a;雾的颜色。Fog Mode&#xff1a;雾效的模式Fog Density&#xff1a;雾效的浓度&#xff0c;取值范围0~1&#xff0c;数值越大雾效浓度越高。。Linear Fog Start&#xff1a;线性雾效开始距离&…

谈谈 Dapr 的优缺点,应用场景,以及未来的发展趋势,生态成熟度

谈谈 Dapr 的优缺点&#xff0c;应用场景&#xff0c;以及未来的发展趋势&#xff0c;生态成熟度 优点缺点应用场景未来发展趋势生态成熟度 本文采用 GPT4 生成&#xff0c;仅供参考。 Dapr 是一个分布式应用程序运行时&#xff0c;其目标是提供一组通用的功能&#xff0c;可以…

我找到了一个生信分析专用服务器!

写在前面 生信分析离不开计算资源&#xff0c;从事生信工作开始&#xff0c;我都在寻找可以满足我开展分析的服务器&#xff0c;不过在寻找过程中发现了以下问题&#xff1a; 如何获得计算资源、部署分析环境、安装生物信息学软件以及保障计算资源的安全和稳定。 当前面临的主要…

SSM框架学习-请求映射路径、请求参数、json数据传送参数以及日期型参数传递

1. 请求映射路径 在进行多人开发&#xff0c;每个人设置不同的请求路径&#xff0c;要解决冲突问题 设置模块名作为请求路径前缀 两种方式 方式一&#xff1a; public class BookController {//请求路径映射RequestMapping("/book/save")ResponseBodypublic String …

新一代企业数字化联盟成立,甄知科技与众多企业“强强联手”搭建品牌服务生态

5月18日&#xff0c;新一代企业数字化联盟&#xff08;以下简称“新一代联盟”&#xff09;成立大会在上海举行。该联盟由包括甄云科技、得帆信息、甄知科技、盖雅工场、甄零科技、易立德信息、鼎医、数划云在内的8家创新型数字化软件科技企业发起&#xff0c;旨在希望通过强强…

【Java入门】数据类型与变量

前言 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐的一位博主。 &#x1f4d7;本文收录于Java入门篇系列&#xff0c;该专栏主要讲解&#xff1a;什么是java、java的数据类型与变…

PyCharm 点击运行,没有执行所有的py文件内容

&#xff08;JDD_KK原创&#xff09; 基于 Pycharm&#xff0c;python3 问题&#xff1a;编写了一个测试工程&#xff0c;创建了多个.py文件。 多个py文件为&#xff1a; data_test/test_datademo.py interface_test/test_interface1.py test_test/test_test.py web_test/test…

【LCD 应用编程】获取LCD屏幕参数信息(分辨率、像素深度、RGB格式)

目录 一、LCD显示的基本原理 1、认识 FrameBuffer 2、理解LCD的分辨率和深度 二、接口函数 ioctl 1、函数声明 2、结构体介绍 三、获取LCD屏的信息&#xff08;分辨率、深度&#xff09; 一、LCD显示的基本原理 1、认识 FrameBuffer FrameBuffer 是帧缓冲&#xff0c;…

[VPX611]基于 6U VPX 总线架构的SATA3.0 高性能数据存储板

板卡概述 VPX611 是一款基于6UVPX 总线架构的高性能数据存储板&#xff0c;该板卡采用2 片XilinxKintex-7 系列FPGA 作为主控单元&#xff0c;FPGA 内嵌RAID 控制器&#xff0c;最大支持8 个mSATA 盘&#xff0c;最大存储容量可以达到8TByte&#xff0c;持续数据写入带宽可以达…

Scrum专业能力之Scrum框架和用敏捷思维管理产品

一、理解和应用Scrum框架 理解和应用Scrum框架&#xff0c;让团队和组织最多30天就可以迭代增量式交付可上线的具有价值的完工产品。成功地应用Scrum框架要求理解和应用Scrum价值观以及经验主义的原则&#xff0c;以便在处理产品交付的内在复杂性的同时&#xff0c;专业地向组…

浑元太极和领域驱动设计-UMLChina建模知识竞赛第4赛季第2轮

DDD领域驱动设计批评文集>> 《软件方法》强化自测题集>> 《软件方法》各章合集>> 参考潘加宇在《软件方法》和UMLChina公众号文章中发表的内容作答。在本文下留言回答&#xff0c;先全部答对者得分&#xff0c;本轮总分为3分。 1. [多选] 开发团队中&am…

在 Visual Studio 2022 中使用 GitHub Copilot chat

本文通过实际应用场景和示例代码展示了 GitHub Copilot Chat 在 Visual Studio 2022 中的优势和特点。最后&#xff0c;鼓励读者在实际工作中尝试使用 Copilot Chat&#xff0c;以提升开发效率和代码质量。希望这些信息和经验能为你在使用GitHub Copilot时提供帮助和启发。 1. …

openssh kex.c拒绝服务漏洞漏洞(CVE-2016-8858)处理

一、漏洞描述 OpenSSH&#xff08;OpenBSD Secure Shell&#xff09;是OpenBSD计划组所维护的一套用于安全访问远程计算机的连接工具。该工具是SSH协议的开源实现&#xff0c;支持对所有的传输进行加密&#xff0c;可有效阻止窃听、连接劫持以及其他网络级的攻击。OpenSSH 6.x版…

leetcode二叉树中的最大路径和(java)

二叉树中的最大路径和 leetcode 124题- 原题链接二叉树中的最大路径和 (hard)解题思路二叉树专题 leetcode 124题- 原题链接 leetcode 124 .二叉树的最大路径和 二叉树中的最大路径和 (hard) 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一…