Kotlin基础(八):泛型

前言

本文主要讲解kotlin泛型,主要包括泛型基础,类型变异,类型投射,星号投射,泛型函数,泛型约束,泛型在Android中的使用。


Kotlin文章列表

Kotlin文章列表: 点击此处跳转查看


目录

在这里插入图片描述


1.1 泛型基础

在 Kotlin 中,泛型是一种类型参数化的机制,它允许我们编写具有通用性的代码。使用泛型,我们可以编写可以在不同类型上工作的代码,而无需为每个具体类型编写重复的代码。

Kotlin 中的泛型使用尖括号 < > 来定义,并且在类型声明中使用角括号来指定类型参数。例如,下面是一个简单的泛型函数的例子:

fun <T> printItem(item: T) {println(item.toString())
}

在这个例子中,<T> 表示这个函数是一个泛型函数,并且 T 是一个类型参数。我们可以在函数内部使用 T 来表示任意类型。在调用 printItem 函数时,编译器会根据实参的类型推断出 T 的具体类型。

下面是一个使用泛型的类的例子:

class Box<T>(val item: T) {fun getItem(): T {return item}
}fun main() {val box = Box("Hello")val item: String = box.getItem()println(item)
}

在这个例子中,Box 类使用泛型类型参数 T,并且有一个泛型函数 getItem 返回类型为 T。在 main 函数中,我们创建了一个 Box<String> 对象,并调用了 getItem 函数来获取其中的值。

除了单个类型参数外,Kotlin 还支持多个类型参数的泛型定义。例如:

class Pair<A, B>(val first: A, val second: B) {// ...
}

在使用泛型时,我们可以限制类型参数的上界。这可以通过使用冒号 : 加上类型约束来实现。例如,我们可以指定一个类型参数必须是某个类的子类,或者实现了某个接口。下面是一个使用类型约束的例子:

fun <T : Number> convertToInt(value: T): Int {return value.toInt()
}

在这个例子中,<T : Number> 指定了类型参数 T 必须是 Number 类的子类。这样,我们可以在函数体内调用 Number 类的方法,例如 toInt

这些是 Kotlin 中泛型的基础知识。通过使用泛型,我们可以编写更具有通用性和复用性的代码,提高代码的灵活性和可读性。


1.2 类型变异

在 Kotlin 中,类型变异(Type Variance)是指在泛型类型中允许子类型关系的灵活性。Kotlin 提供了几种类型变异的修饰符,用于在使用泛型时指定类型参数的变异方式。这些修饰符包括:inout 和默认(不使用修饰符)。

  1. in:逆变(Contravariant)
    使用 in 修饰符声明的类型参数只能用作输入(即参数类型),不能用作输出(即返回类型)。它允许我们使用指定的类型参数的超类作为泛型类型的实参。在函数中,逆变类型参数只能作为方法的参数类型。

    例如,考虑一个逆变的接口 Comparable

    interface Comparable<in T> {fun compare(other: T): Int
    }
    

    这里的 in 修饰符表示类型参数 T 可以是方法的输入类型。这意味着我们可以使用 Comparable 接口的一个子类作为方法参数的类型,例如:

    fun sort(list: List<Comparable<in String>>) {// 排序逻辑...
    }
    

    在这个例子中,sort 函数接收一个 List,其中的元素类型是 Comparable<in String>,也就是说,我们可以传递 Comparable<String>Comparable<Any> 等类型的实例。

  2. out:协变(Covariant)
    使用 out 修饰符声明的类型参数只能用作输出(即返回类型),不能用作输入(即参数类型)。它允许我们使用指定的类型参数的子类作为泛型类型的实参。在函数中,协变类型参数只能作为方法的返回类型。

    例如,考虑一个协变的接口 Producer

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

    这里的 out 修饰符表示类型参数 T 可以是方法的输出类型。这意味着我们可以将 Producer 接口的一个超类赋值给类型为 Producer<out String> 的变量,例如:

    fun getProducer(): Producer<out String> {// 返回 Producer 的一个子类实例
    }
    

    在这个例子中,getProducer 函数的返回类型是 Producer<out String>,也就是说,我们可以将其返回值赋给类型为 Producer<String>Producer<Any> 等类型的变量。

  3. 默认
    如果没有指定任何修饰符,则类型参数既可以用作输入(参数类型),也可以用作输出(返回类型)。这种情况下,类型参数是不变的(Invariant)。

    例如,考虑一个不变的类 Box

    class Box<T>(val item: T) {fun getItem(): T {return item}
    }
    // 这里的类型参数 `T` 没有任何修饰符,因此它是不变的。在这种情况下,我们只能使用确切的类型作为泛型类型的实参。
    val box: Box<String> = Box("Hello")
    

通过使用逆变、协变和不变的修饰符,Kotlin 中的泛型提供了更灵活的类型参数关系,以便更好地处理不同的使用场景。


1.3 类型投射

在 Kotlin 中,类型投射(Type Projections)是指在使用泛型类型时对泛型参数的灵活性处理。类型投射允许我们在使用泛型类型时指定类型参数的上界或下界,从而在特定的上下文中对泛型类型进行限制。

Kotlin 中有三种类型投射的方式:

  1. 上界投射(Upper Bounds Projection):使用 out 关键字
    当我们只需要从泛型类型中获取值,而不需要修改该值时,我们可以使用上界投射。使用 out 关键字,我们可以指定类型参数的上界。这样,我们可以将泛型类型的实例赋值给类型参数的超类型。

    例如,考虑一个定义了 Producer 接口的泛型类:

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

    在这个例子中,out 关键字指定了类型参数 T 的上界,表示我们只能从 Producer 实例中获取 T 类型的值,而不能修改它。

  2. 下界投射(Lower Bounds Projection):使用 in 关键字
    当我们只需要向泛型类型中传递值,而不需要获取值时,我们可以使用下界投射。使用 in 关键字,我们可以指定类型参数的下界。这样,我们可以将泛型类型的实例赋值给类型参数的子类型。

    例如,考虑一个定义了 Consumer 接口的泛型类:

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

    在这个例子中,in 关键字指定了类型参数 T 的下界,表示我们只能向 Consumer 实例中传递类型为 T 或其子类型的值,而不能传递超类型的值。

  3. 星投射(Star Projection):使用 * 关键字
    当我们既不需要从泛型类型中获取值,也不需要向泛型类型中传递值时,我们可以使用星投射。使用星投射,我们可以在使用泛型类型时忽略类型参数。

    例如,考虑一个定义了 Box 类的泛型类:

    class Box<T>(val item: T)
    

    在某些情况下,我们可能不关心具体的类型参数,而只是希望使用一个泛型类型的实例。这时,我们可以使用星投射来表示不关心具体类型参数的情况。

    val box: Box<*> = Box("Hello")
    

    在这个例子中,Box<*> 表示一个未知的类型参数,我们可以使用该实例,但无法获取其中的具体类型。

类型投射允许我们在使用泛型类型时灵活地指定类型参数的上界或下界,从而更好地适应不同的使用场景。


1.4 星号投射

在 Kotlin 中,星号投射(Star Projection)是一种用于处理泛型类型的特殊语法。它通常用于在某些情况下,你可能不需要或无法知道泛型类型的确切参数。星号投射允许你使用未知类型的泛型参数,并且在代码中只能执行一些有限的操作。

星号投射使用星号 (*) 表示未知类型。它可以应用于泛型类、接口和方法。

下面是一个星号投射的示例:

假设有一个简单的泛型类 Box,定义如下:

class Box<T>(private val item: T) {fun getItem(): T {return item}
}

现在,假设你有一个泛型类 Container,它包含一个 Box 的列表:

class Container<T>(private val boxes: List<Box<T>>) {fun getFirstItem(): T {return boxes[0].getItem()}
}

假设你有一个 Container 的实例,但是你并不知道 Container 的泛型类型参数 T 是什么。这时,你可以使用星号投射来处理未知类型。

fun processContainer(container: Container<*>) {val item = container.getFirstItem()// 在这里,由于我们不知道 Container 的泛型类型参数 T 是什么,只能执行一些有限的操作,如打印或进行简单处理。println("First item: $item")
}

在上面的示例中,Container<*> 表示一个具有未知泛型类型参数的 Container 实例。我们只能调用返回 T 类型的方法(在这里是 getFirstItem()),但无法向其中添加新的元素(因为我们不知道它的确切类型)。

需要注意的是,使用星号投射通常是在处理未知泛型类型的情况下使用的,而且通常涉及一些限制,因为编译器无法确切知道类型的信息。因此,在使用星号投射时,必须小心谨慎,确保你只执行合法且安全的操作。


1.5 泛型函数

1.5.1 泛型函数的简介

在 Kotlin 中,你可以创建泛型函数,这些函数允许你在调用时指定参数类型,并且在函数定义中可以使用这些类型参数进行通用的操作。泛型函数能够增加代码的重用性和类型安全性,因为它们可以适用于多种类型而不必为每个类型编写多个函数。

Kotlin 中定义泛型函数使用尖括号 (<>) 来声明泛型类型参数,并将它们放在函数名之前。下面是一个简单的示例:

// 在函数名前声明泛型类型参数 <T>
fun <T> printItem(item: T) {println(item)
}

在这个示例中,我们定义了一个名为 printItem 的泛型函数,它接收一个类型参数为 T 的参数 item,并简单地打印它。在函数体内,你可以像使用普通类型一样使用类型参数 T

现在,你可以在调用 printItem 函数时指定参数的类型,编译器会根据传入的参数类型自动推断出类型参数 T 的具体类型:

printItem("Hello, World!") // 调用时,Kotlin 会推断 T 为 String 类型
printItem(42) // 调用时,Kotlin 会推断 T 为 Int 类型
printItem(true) // 调用时,Kotlin 会推断 T 为 Boolean 类型

除了单个类型参数,你也可以在函数中定义多个泛型类型参数,这使得泛型函数更加灵活:

// 定义一个泛型函数,接收两个类型参数,并返回它们的 Pair
fun <T, U> createPair(first: T, second: U): Pair<T, U> {return Pair(first, second)
}fun main() {val pair1 = createPair(10, "Hello")val pair2 = createPair(true, 3.14)println(pair1) // 输出: (10, Hello)println(pair2) // 输出: (true, 3.14)
}

以上就是 Kotlin 中定义泛型函数的基本语法和用法。泛型函数在处理通用算法或容器类型时特别有用,因为它们能够适用于不同类型的数据,提供更灵活和类型安全的代码。


1.5.2 kotlin泛型函数与java泛型函数对比

Kotlin 和 Java 都支持泛型函数,但它们在语法和使用上有一些不同。下面我们将对 Kotlin 泛型函数和 Java 泛型函数进行对比:

  1. 语法差异:

    Kotlin 泛型函数:

    fun <T> genericFunction(item: T): T {// 函数体
    }
    

    Java 泛型函数:

    public <T> T genericFunction(T item) {// 函数体
    }
    

    Kotlin 使用 <T> 放在函数名前来声明泛型类型,而 Java 则使用 <T> 放在返回类型之前。

  2. 类型推断:

    Kotlin 泛型函数:

    val result = genericFunction("Hello")
    // 在这里,Kotlin 可以推断出泛型类型 T 为 String
    

    Java 泛型函数:

    String result = genericFunction("Hello");
    // Java 不能自动推断泛型类型,需要显式指定类型
    

    Kotlin 的类型推断机制通常更加智能,能够自动推断泛型参数类型,而 Java 需要显式指定泛型类型。

  3. 通配符和星号投射:

    Kotlin 泛型函数:

    fun processList(list: List<*>) {// 函数体
    }
    

    Java 泛型函数:

    public void processList(List<?> list) {// 函数体
    }
    

    Kotlin 使用星号 * 表示未知类型(星号投射),而 Java 使用 ? 表示通配符。

  4. 多重约束:

    Kotlin 泛型函数:

    fun <T : Number> processNumber(item: T): T {// 函数体
    }
    

    Java 泛型函数:

    public <T extends Number> T processNumber(T item) {// 函数体
    }
    

    Kotlin 使用 : 来指定泛型类型的约束,而 Java 使用 extends 关键字。

总体来说,Kotlin 和 Java 的泛型函数在基本概念上是相似的,但具体的语法和使用方式有所不同。如果你熟悉 Java 的泛型,学习 Kotlin 的泛型应该相对容易,因为 Kotlin 是建立在 Java 基础之上并进行了一些改进。


1.6 泛型约束

在 Kotlin 中,你可以对泛型进行约束,以限制泛型类型参数的范围。泛型约束可以帮助你在泛型函数或泛型类中使用特定类型的功能,提高类型安全性并允许更具体的操作。

以下是在 Kotlin 中定义泛型约束的一些方法:

  1. 上界约束(Upper Bounds):

    通过使用 : 来指定泛型类型的上界,你可以限制泛型类型参数只能是指定类或其子类。这意味着类型参数必须是指定类或其子类的实例。

    // 示例:泛型类型参数 T 必须是 Number 类或其子类的实例
    fun <T : Number> printNumberInfo(number: T) {println("Value: ${number.toDouble()}")
    }
    
  2. 多重约束(Multiple Bounds):

    Kotlin 支持多重约束,即指定一个泛型类型参数必须满足多个约束条件。你可以使用 where 关键字来声明多个约束条件。

    // 示例:泛型类型参数 T 必须是 Number 类或其子类,并且实现了 Comparable 接口
    fun <T> printInfo(item: T) where T : Number, T : Comparable<T> {println("Value: $item")
    }
    
  3. 非空约束(Not-null Constraint):

    通过使用 T : Any 来约束泛型类型参数为非空类型。这样,你可以确保泛型参数不接受可空类型。

    // 示例:泛型类型参数 T 不能为可空类型
    fun <T : Any> processItem(item: T) {// 处理非空类型的 item
    }
    
  4. 泛型函数中的类型约束:

    在泛型函数中,你也可以对泛型参数进行约束,就像在泛型类中一样。使用 : 和类型名称来指定约束。

    // 示例:泛型函数中的类型约束
    fun <T> processList(list: List<T>) where T : CharSequence, T : Comparable<T> {// 在这里,T 必须是 CharSequence 和 Comparable<T> 的子类型// 可以使用 CharSequence 和 Comparable<T> 接口中定义的功能
    }
    

这些约束可以帮助你在泛型函数或泛型类中获得更具体的类型信息,并确保类型的安全性。在使用约束时,应该选择最合适的约束以满足你的需求,并根据实际情况来决定是否需要单个约束还是多重约束。


1.7 泛型在Android中的使用

在 Android 开发中,Kotlin 的泛型可以在许多地方使用,例如列表适配器、网络请求、异步任务等。这里我将以列表适配器为例来演示 Kotlin 泛型在 Android 中的使用。

假设你有一个简单的数据类 Person 表示人员信息:

data class Person(val name: String, val age: Int)

现在,我们要在 Android 中展示一个 RecyclerView,显示一组人员信息。我们将使用泛型来创建一个通用的列表适配器,可以在不同的地方重用。

首先,创建一个泛型适配器类 GenericAdapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerViewclass GenericAdapter<T>(private val items: List<T>,private val itemLayoutResId: Int,private val bindHolder: (item: T, view: View) -> Unit
) : RecyclerView.Adapter<GenericAdapter<T>.ViewHolder>() {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {val view = LayoutInflater.from(parent.context).inflate(itemLayoutResId, parent, false)return ViewHolder(view)}override fun onBindViewHolder(holder: ViewHolder, position: Int) {val item = items[position]bindHolder(item, holder.itemView)}override fun getItemCount(): Int {return items.size}inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
}

在这个适配器类中,我们使用泛型 T 来表示适配器中的数据项类型。items 参数是一个泛型类型的列表,用于存储要展示的数据。itemLayoutResId 参数表示列表项的布局资源 ID,bindHolder 参数是一个函数,用于将数据绑定到列表项的视图上。

现在,我们可以在 MainActivity 中使用这个通用的列表适配器来显示人员信息:

import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val peopleList = listOf(Person("John Doe", 30),Person("Jane Smith", 25),Person("Michael Johnson", 40))recyclerView.layoutManager = LinearLayoutManager(this)recyclerView.adapter = GenericAdapter(peopleList, R.layout.item_person) { person, view ->val nameTextView = view.findViewById<TextView>(R.id.nameTextView)val ageTextView = view.findViewById<TextView>(R.id.ageTextView)nameTextView.text = person.nameageTextView.text = person.age.toString()}}
}

在上面的例子中,我们使用 GenericAdapter 来展示人员信息,将每个人员的姓名和年龄显示在列表项中。由于我们使用了泛型,这个通用适配器可以用于显示其他类型的数据,只需更改数据源和布局即可。
这样,我们通过泛型的使用,实现了一个通用的列表适配器,可以在 Android 中更方便地重用。

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

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

相关文章

Unity XML1——XML基本语法

一、XML 概述 ​ 全称&#xff1a;可拓展标记语言&#xff08;EXtensible Markup Language&#xff09; ​ XML 是国际通用的&#xff0c;它是被设计来用于传输和存储数据的一种文本特殊格式&#xff0c;文件后缀一般为 .xml ​ 我们在游戏中可以把游戏数据按照 XML 的格式标…

JAVA线上问题排查降龙十八掌

现场问题一般有以下几种问题 CPU,磁盘&#xff0c;内存&#xff0c;GC问题&#xff0c;网络 同时例如jstack、jmap等工具也是不囿于一个方面的问题的&#xff0c;基本上出问题就是df、free、top 三连&#xff0c;然后依次jstack、jmap伺候&#xff0c;具体问题具体分析即可。 …

windows中文界面乱码问题

我的便携是内部返修机&#xff0c;买来时就是英文版&#xff0c;在设置中改成简体中文就可以了&#xff0c;与中文版没有什么区别&#xff0c;已经升级成win11。windows自身的应用、360之类的界面都能正常显示&#xff0c;但是个别应用总是乱码&#xff0c;根据客服的提示设置一…

非线性质量弹簧阻尼器的神经网络仿真研究(Matlab代码Simulink仿真实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

关于在虚拟机CentOS7的Docker下安装Oracle

这不三阶段了&#xff0c;要上Oracle了&#xff0c;感觉这个班卷的程度到位。二阶段我就上了ElementUI和MyBatis&#xff0c;项目也是用这些技术写的&#xff0c;整体钻研程度还行。于是布置了两个任务&#xff1a;在windows下安一下Oracle&#xff0c;在windows下安装Oracle那…

python安装第三方包的两种方式

最近研究QQ空间、微博的&#xff08;爬虫&#xff09;模拟登录&#xff0c;发现都涉及RSA算法。于是需要下一个RSA包&#xff08;第三方包&#xff09;。折腾了很久&#xff0c;主要是感觉网上很多文章对具体要在哪里操作写得不清楚。这里做个总结&#xff0c;以免自己哪天又忘…

GRE TAP的工作原理与5G工业物联网中的应用

随着互联网新技术的发展以及智能化水平的提高&#xff0c;各企业对实时数据传输的需求也在不断提升&#xff0c;企业愈发重视数据中心的建设&#xff0c;以保障企业内网数据安全。 GRE&#xff08;Generic Routing Encapsulation&#xff0c;通用路由封装&#xff09;协议属于…

作为一名程序员,IVX你值得拥有

目录 一、IVX是什么 二、IVX编程盒子——低代码平台的首个硬件产品 iVX做硬件的原因 iVX自身特点——安全、方便、高效、低耗 三、IVX编程盒子自带的Demo系统 1. 问题反馈、在线沟通和工单处理系统 2. 大屏幕监管平台 四、IVX和其他代码平台的区别 五、低代码未来的发展…

使用sftp

一、背景 新项目组前端部署方式是Build打包生成dist文件&#xff0c;交由后端部署。后来知道了vscode安装sftp前端可以自行部署。 二、实操 1、vscode安装sftp 2、 配置 ①F1 / ctrlshiftp ②命令行输入sftp -> 选择 sftp: Config ③配置信息介绍 {"name"…

Qt5.14.2+VS2019配置MSVC2017

问题&#xff1a; The compiler " Microsoft Visual C Compiler 16 . 11 . 32106 . 194 ( amd64 x86 )( x86-windows-msvc2019-pe-32bit ) cannot produce code for the Qt version " Qt5.14.2 MSVC2017 64bit " ( x86-windows-msvc2017-pe-64bit 编译器“…

钉钉和金蝶云星空接口打通对接实战

钉钉和金蝶云星空接口打通对接实战 对接系统&#xff1a;钉钉 钉钉是阿里巴巴集团打造的企业级智能移动办公平台&#xff0c;是数字经济时代的企业组织协同办公和应用开发平台。钉钉将IM即时沟通、钉钉文档、钉闪会、钉盘、Teambition、OA审批、智能人事、钉工牌、工作台深度整…

制定机器学习规划路线:从入门到专业

文章目录 &#x1f340;第一阶段&#xff1a;入门基础&#x1f340;了解机器学习概念&#x1f340;学习编程和数学基础&#x1f340;探索经典机器学习算法&#x1f340;完成实践项目 &#x1f340;第二阶段&#xff1a;深入学习&#x1f340; 掌握深度学习基础&#x1f340;学习…

ceph-mon运行原理分析

一、流程&#xff1a;ceph-deploy部署ceph-mon组建集群 1.ceph-deploy部署ceph-mon的工作流程及首次启动 1&#xff09;通过命令创建ceph-mon&#xff0c;命令为&#xff1a;ceph-deploy create mon keyring def mon(args):if args.subcommand create:mon_create(args)elif…

查找-多路查找详解篇

多路查找树 多路查找树&#xff08;Multway Search Tree&#xff09;是一种高级的树形数据结构&#xff0c;它 允许每个节点有多个子节点&#xff08;通常大于等于2&#xff09;。多路查找树的每个节点 可以存储多个关键字和对应的值。分类 2-3树&#xff08;2-3 Tree&#x…

什么是多运行时架构?

服务化演进中的问题 自从数年前微服务的概念被提出&#xff0c;到现在基本成了技术架构的标配。微服务的场景下衍生出了对分布式能力的大量需求&#xff1a;各服务之间需要相互协作和通信&#xff0c;以及共享状态等等&#xff0c;因此就有了各种中间件来为业务服务提供这种分…

逻辑斯特回归

*分类是离散的&#xff0c;回归是连续的 下载数据集 trainTrue&#xff1a;下载训练集 逻辑斯蒂函数保证输出值在0-1之间 能够把实数值映射到0-1之间 导函数类似正态分布 其他饱和函数sigmoid functions 循环神经网络经常使用tanh函数 与线性回归区别 塞戈马无参数&#x…

STM32CubeMX v6.9.0 BUG:FLASH_LATENCY设置错误导致初始化失败

背景 今天在调试外设功能时&#xff0c;发现设置了使用外部时钟之后程序运行异常&#xff0c;进行追踪调试并与先前可以正常运行的项目进行对比之后发现这个问题可能是由于新版本的STM32CubeMX配置生成代码时的BUG引起的。 测试环境 MCU: STM32H750VBT6 STM32CubeIDE: Versi…

大数据处理架构详解:Lambda架构、Kappa架构、流批一体、Dataflow模型、实时数仓

前言 本文隶属于专栏《大数据理论体系》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见大数据理论体系 姊妹篇 《分布式数据模型详解&#xff1a;OldSQL &…

【Linux从入门到精通】进程的控制(进程退出+进程等待)

本篇文章主要讲述的是进程的退出和进程等待。希望本篇文章的内容会对你有所帮助。 文章目录 一、fork创建子进程 1、1 在创建子进程中操作系统的作用 1、2 写时拷贝 二、进程终止 2、1 常见的进程退出 2、2 进程的退出码 2、2、1 运行结果正确实例 2、2、2 运行结果不正确实例…

购物车功能实现(小兔鲜儿)【Vue3】

购物车 流程梳理和本地加入购物车实现 购物车业务逻辑梳理拆解 整个购物车的实现分为两个大分支, 本地购物车操作和接口购物车操作由于购物车数据的特殊性,采取Pinia管理购物车列表数据并添加持久化缓存 本地购物车 - 加入购物车实现 添加购物车 基础思想&#xff1a;如果…