当前位置: 首页 > news >正文

[读书日志]从零开始学习Chisel 第二篇:Scala的变量与函数(敏捷硬件开发语言Chisel与数字系统设计)

第一篇icon-default.png?t=O83Ahttps://blog.csdn.net/m0_74021449/article/details/144887921

2.2 Scala的变量及函数

2.2.1变量定义与基本类型

变量声明

变量首次定义必须使用关键字var或者val,二者的区别是val修饰的变量禁止被重新赋值,它是一个只读的变量。首次定义变量时必须赋值进行初始化。var类型的变量重新赋值时新旧必须是同一个类型,而val类型变量无法被重新赋值。变量定义具有覆盖性,后声明的变量会覆盖前面的变量。

Scala推荐使用val定义变量,函数式编程的思想之一就是传入函数的参数不应该改变。需要说明的是,使用val定义的变量并不是不可变,而是这个指向关系不可变。当这个变量被声明,变量指向的对象就是唯一确定的,但这个对象本身可以改变,只是变量指向的位置不可变。

基本类型

Scala作为一种静态语言,在编译时会检查每个对象的类型,类型不匹配的非法操作会报错。Scala定义了一些标准类型:

类型说明
Byte8bit有符号整数,补码表示,范围是-27~27-1
Short16bit有符号整数,补码表示,范围是-215~215-1
Int32bit有符号整数,补码表示,范围是-231~231-1
Long64bit有符号整数,补码表示,范围是-263~263-1
Char16bit无符号字符,Unicode编码表示,范围是0~216-1
String字符串类型,属于java.bang包
Float32bit单精度浮点数
Double64bit双精度浮点数
Boolean布尔值,true or false

定义变量时可以指定类型,也可以让编译器自动推断。显式指定类型的示例:

scala> val x: Int = 123
val x: Int = 123scala> val y: Long = 123
val y: Long = 123

整数字面量

如果单独出现数字,没有任何说明,默认推断为Int类型;结尾有l或L的推断为Long类型,以0x开头的认为是十六进制,不区分大小写。Byte和Short类型需要显示指定:

scala> val x = 100
val x: Int = 100
​
scala> val y = 100L
val y: Long = 100
​
scala> val z: Byte = 200
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |val z: Byte= 200|             ^^^|             Found:    (200 : Int)|             Required: Byte|| longer expla

Byte类型最大不超过127,超过限制的赋值将报错

浮点数字面量

浮点数字面量都是十进制的,默认是Double类型,En或en表示科学计数法10的n次方,末尾加一个f或F表示Float,D或d表示Double。Double字面量不能赋值给Float类型变量。

scala> val x: Float = -3.2
val x: Float = -3.2
​
scala> val x = -3.2
val x: Double = -3.2
​
scala> val x: Float = 3.2D
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |val x: Float = 3.2D|               ^^^^|               Found:    (3.2d : Double)|               Required: Float|| longer explanation available when compiling with `-explain`
1 error found

字符字面量和字符串字面量

以单引号括住的一个字符表示一个字符字面量,采用Unicode编码,也可以使用'\u编号'来构建一个字符,本书说明Unicode编码可以出现在名称命名处,但在最新版本Scala编译器中会报错:

scala> val a = 'a'
val a: Char = a
​
scala> val \u0041 = 'a'
-- [E032] Syntax Error: ------------------------------------------------------------------------------------------------
1 |val \u0041 = 'a'|           ^|           pattern expected|| longer explanation available when compiling with `-explain`

字符串字面量是用双引号“”括住的字符序列,长度是任意的。字符和字符串都支持转义字符。

字符串插值

表达式可以被嵌入在字符串字面量中被求值,有三种实现方法,一种是s插值器,一种是raw插值器,一种是f插值器。

s插值器形如 s"……${表达式}……"其中花括号可以不加,但只会识别美元符号到首个非标识字符(字母、数字、下划线和操作符的组合交标识符,以及字符串)对于非标识字符如果想要求值,必须使用花括号:

scala> val name = "Jia"
val name: String = Jiascala> s"Name = $name"
val res3: String = Name = Jiascala> s"Result = ${1+2}"
val res4: String = Result = 3

raw插值器和s插值器类似,区别是不识别转义字符。

f插值器使用方法更灵活,支持格式控制:

scala> printf(f"${math.Pi}%.5f")
3.14159~

2.2.2函数及其几种形式

函数的定义

不多说,直接看代码:

scala> def max(x : Int, y: Int): Int = {| if(x > y)| x| else| y| }
def max(x: Int, y: Int): Int

说明:x,y是输入参数(形参)后面跟的是它们的类型;Int={}是函数体,表示返回是一个Int类型整数。

备注:左侧的|只是编译器自己生成的,用于多行的代码,并不是语法体系中的一部分。

  1. 分号推断:语句末尾的分号是可选的,编译器会自动推断分号。如果一行有多条语句,则必须用分号隔开。

  2. 函数的返回结果:return关键字是可选的,编译器自动为函数体中的最后一个表达式加上return,建议不要显示声明return。返回结果的类型也可以自动推断,也就是说上面的Int = {},Int也是可以省略的。Uint类型表示无返回值,它不是必须的,编译器也可以自动推断;但如果显式声明Uint,则即便有可以返回的值也不会返回任何值。

  3. 等号与函数体:函数体是花括号括起来的部分,里面有多条语句,可以自动推断分号,返回最后一个表达式。当函数的返回类型没有显示声明,等号可以省略,但此时返回类型会变成Uint,建议不要省略等号,并且用显示声明返回类型。

  4. 无参函数:无参函数可以写空括号作为参数列表,也可以不写;但如果没有空括号,调用的时候禁止写空括号。

方法

方法指定义在class,object,trait中的函数,成为成员函数或方法,这与其他面向对象特性的语言一致。

嵌套函数

函数体内部可以嵌套定义内部函数,但无法被外界访问。

函数字面量

函数式编程认为函数的地位和一个Int值,String值是一样的,因此函数也可以成为一个函数的参数或返回值,也可以把函数赋值给一个变量。函数字面量是一种匿名函数,它可以存储在变量中,成为函数参数,或者当作返回值返回,定义形式是:

{参数1:参数1类型,参数2:参数2类型...} => {函数体}

它可以更精简地使用,用下划线作为占位符替代参数,只保留函数体:

scala> val f = (_: Int) + (_: Int)
val f: (Int, Int) => Int = Lambda/0x00000003015d55a8@6816b0cbscala> f(1,2)
val res5: Int = 3

用def定义的函数和函数字面量都可以以函数为参数,返回函数。

scala> val add = (x:Int) => {(y:Int) => x + y}
val add: Int => Int => Int = Lambda/0x00000003015d6348@20f1e26scala> add(1)(10)
val res6: Int = 11

这里是函数的嵌套,第一个函数表示输入是x,类型是Int,函数体是(y:Int)=> x+y这是一个函数字面量,它的输入是y,类型是Int,函数体是x+y,并且把这个表达式结果返回。如果调用add(1),则返回的是(y:Int)=>1+y这个函数字面量。

scala> def aFunc(f:Int => Int) = f(1) + 1
def aFunc(f: Int => Int): Int
​
scala> aFunc(x=>x+1)
val res7: Int = 3

aFunc的参数f是一个函数,它的输入类型是Int,返回类型也是Int,调用时传入的参数是函数字面量x=>x+1,首先计算f(1)=2,再计算返回值是3。

部分应用函数

上面的函数字面量实现了函数作为一等值的功能,使用def定义的函数也具有相同的功能,只不过需要借助部分应用函数的形式来实现。部分应用函数的意思就是给出函数的一部分参数,使其可以赋值给变量或者当作函数参数进行传递。废话不多数,直接上代码:

scala> def sum(x:Int,y:Int,z:Int) : Int = {x + y + z}
def sum(x: Int, y: Int, z: Int): Int
​
scala> val a1 = sum(4,5,6)
val a1: Int = 15
​
scala> val a2 = sum(4,_:Int,6)
val a2: Int => Int = Lambda/0x000000030167d3a0@c3acda3
​
scala> a2(5)
val res12: Int = 15
​
scala> val a3 = sum _
1 warning found
-- Warning: ------------------------------------------------------------------------------------------------------------
1 |val a3 = sum _|         ^^^^^|         The syntax `<function> _` is no longer supported;|         you can simply leave out the trailing ` _`
val a3: (Int, Int, Int) => Int = Lambda/0x00000003016767e0@2c427287
​
scala> val a3 = sum
val a3: (Int, Int, Int) => Int = Lambda/0x0000000301676e10@68603829
​
scala> a3(4,5,6)
val res9: Int = 15

注意:书中的写法 sum _在最新版的编译器中不被支持,现在无需写下划线,只需要把函数名直接赋值给变量即可直接调用。

scala> def needSum(f:(Int,Int,Int) => Int) = f(1,2,3)
def needSum(f: (Int, Int, Int) => Int): Int
​
scala> needSum(sum)
val res13: Int = 6

这里我们已经逐渐能够感受到函数式编程的魅力,当理解这种调用方式后将会有很灵活的应用。

闭包

一个函数除了使用它的参数以外,还可以使用定义在函数以外的其他变量,其中函数的参数成为绑定变量,函数以外的变量称为自由变量,这样的函数称为闭包。函数捕获的自由变量是函数定义之前的自由变量,若后面出现新的同名自由变量将前面的自由变量将其覆盖,函数与其无关。但如果自由变量是用var创建的可变对象,那么闭包随之改变。

scala> var a1 = 1
var a1: Int = 1
​
scala> val a2 = 100
val a2: Int = 100
​
scala> val add1 = (x : Int) => x + a1
val add1: Int => Int = Lambda/0x000000030167fb08@23b456ac
​
scala> val add2 = (x : Int) => x + a2
val add2: Int => Int = Lambda/0x00000003016843f0@525b416f
​
scala> add1(1)
val res14: Int = 2
​
scala> add2(1)
val res15: Int = 101
​
scala> a1 = 100
a1: Int = 100
​
scala> add1(1)
val res16: Int = 101
​
scala> var a1 = 1
var a1: Int = 1
​
scala> add1(1)
val res17: Int = 101
​
scala> val a2 = 1
val a2: Int = 1
​
scala> add2(1)
val res18: Int = 101

阅读这段程序的对比已经很明显地了解到它的性质。在后面改变var变量的值,闭包随之改变,但对于var和val变量重新定义将前面的覆盖,闭包的值不会随之改变。

函数的特殊调用形式

  1. 具名参数:函数调用时传入的参数是按照先后顺序传递的,但如果显式声明参数的名字,可以无视参数顺序。按位置传递的参数和按名字传递的参数可以混用。

  2. 默认参数值:函数定义时可以给参数一个默认值,如果调用函数缺省了这个参数,会使用默认值。

  3. 重复参数:允许把函数的最后一个参数标记为重复参数,形式在最后一个参数的类型后面加上星号。

柯里化

对于大多数编程语言而言,函数只能有一个参数列表,但是列表中可以有若干用逗号间隔的参数。Scala的特性柯里化允许一个函数可以有任意个参数列表,它与另一个语法搭配使用,即当参数列表中只有一个参数时,调用该函数时允许单个参数不用圆括号括起来,改用花括号也可以。

scala> def add(x:Int)(y:Int)(z:Int) = x+y+z
def add(x: Int)(y: Int)(z: Int): Intscala> add(1)
val res19: Int => Int => Int = Lambda/0x0000000301686b40@7ece1800scala> add(1)(2)
val res20: Int => Int = Lambda/0x00000003016872f0@3b3e9814scala> add(1)(2)(3)
val res21: Int = 6scala> add(1)(2){3}
val res22: Int = 6scala> add{1}(2)(3)
val res23: Int = 6

在这里我们看出来其实柯里化就是把它处理成了一个嵌套的函数。

传名参数

如果一个函数是无参函数,调用函数时,传递进去的函数字面量可以只写函数体。

//常规调用方法
scala> val a1 = 1
val a1: Int = 1
​
scala> val a2 = 2
val a2: Int = 2
​
scala> def add(f: () => Int) = {a1 + a2 + f()}
def add(f: () => Int): Int
​
scala> add(() => 1)
val res24: Int = 4
​
//传名参数调用方法
scala> def add2(f: => Int) = {a1 + a2 + f}
def add2(f: => Int): Int
​
scala> add2(1)
val res26: Int = 4

注:这里传入的f函数是一个没有输入,直接返回传入的值的函数。

这两种版本都是在使用到传入的函数时才会计算这个函数中的表达式,但如果改写成下面这样:(去掉=>),那么就变成先计算表达式再传入值。

scala> def add3(f:Boolean) = {| if(f)| a1 + a2| else| 0| }
def add3(f: Boolean): Int
​
scala> add3(1<2)
val res27: Int = 3
​
scala> add3(1>2)
val res28: Int = 0
​
scala> add3(1/0)
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |add3(1/0)|     ^^^|     Found:    Int|     Required: Boolean|| longer explanation available when compiling with `-explain`
1 error found

相关文章:

[读书日志]从零开始学习Chisel 第二篇:Scala的变量与函数(敏捷硬件开发语言Chisel与数字系统设计)

第一篇https://blog.csdn.net/m0_74021449/article/details/144887921 2.2 Scala的变量及函数 2.2.1变量定义与基本类型 变量声明 变量首次定义必须使用关键字var或者val&#xff0c;二者的区别是val修饰的变量禁止被重新赋值&#xff0c;它是一个只读的变量。首次定义变量时…...

Unity:删除注册表内的项目记录

然后WinR按键输入regedit 打开注册表 在注册表 HKEY CURRENT USER—>SOFTWARE—>Unity—>UnityEditor—>DefaultCompany —>language_Test 中&#xff0c;删除我们的之前存储的语言环境数据。在 “ 三、文本调用和替换 ” 测试时已经将语言环境存储到注册表中了…...

【记录】东南大学研究生24-25秋季 学位英语考试

上午刚考完学位英语&#xff0c;感觉一般&#xff0c;反正就是能过&#xff0c;但是也不是考的特别好&#xff0c;在备考的过程中的一些资料也感谢很多人的分享&#xff0c;我这边也把24年的期末说明放一份吧 其他ppt和资料github一个大佬整理了&#xff0c;在这里 然后也留下…...

LabVIEW四边形阻抗继电器

基于LabVIEW开发了四边形阻抗继电器&#xff0c;该系统主要应用于电力系统的距离保护中。四边形阻抗继电器在克服短路点过渡电阻的影响及躲避负荷阻抗方面展现出优良的特性。通过LabVIEW图形化编程环境实现的该系统&#xff0c;具备用户友好界面和简便的操作流程&#xff0c;有…...

计算机网络(第8版)第3章课后习题--透明传输

【3-11】 试分别讨论以下各种情况在什么条件下是透明传输&#xff0c;在什么条件下不是透明传 输。(提示&#xff1a;请弄清什么是“透明传输”,然后考虑能否满足其条件。) (1)普通的电话通信。 (2)互联网提供的电子邮件服务。 解 答 &#xff1a; 透明传输是指在数据传输…...

极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现

极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现 目录 极限学习机 (Extreme Learning Machine, ELM) 算法详解与PyTorch实现1. 极限学习机 (ELM) 算法概述1.1 单隐层前馈神经网络1.2 ELM的优势2. ELM的核心技术2.1 模型定义2.2 随机初始化2.3 最小二乘法2.4…...

Hbuilder ios 离线打包sdk版本4.36,HbuilderX 4.36生成打包资源 问题记录

1、打包文档地址https://nativesupport.dcloud.net.cn/AppDocs/usesdk/ios.html#%E9%85%8D%E7%BD%AE%E5%BA%94%E7%94%A8%E7%89%88%E6%9C%AC%E5%8F%B7 2、配置应用图标 如果没有appicon文件&#xff0c;此时找到 Assets.xcassets 或者 Images.xcassets(看你sdk引入的启动文件中…...

实验四 数组和函数

实验名称 实验四 数组和函数 实验目的 &#xff08;1&#xff09;掌握一维、二维数组以及字符数组的定义、元素引用和编程方法。 &#xff08;2&#xff09;掌握字符串常用程序的设计方法。 &#xff08;3&#xff09;掌握函数定义和调用的方法&#xff0c;以及函数参数传…...

基于安卓14 的ANR dump信息原理

首先以 service 处理超时逻辑来分析 1&#xff09;service timeout调用到anr 的逻辑&#xff1a; /frameworks/base/services/core/java/com/android/server/am/ActiveServices.java 5827 void scheduleServiceTimeoutLocked(ProcessRecord proc) { 5828 if (…...

C++ volatile(八股总结)

答&#xff1a;跟编译器优化有关&#xff0c;告诉编译器每次操作该变量时一定要从内存中真正取出&#xff0c;而不是使用已经存在寄存器中的备份。 volatile是一个类型限定符&#xff0c;用来告诉编译器&#xff0c;某个变量的值可能在任何时刻发生变化&#xff0c;因此&#…...

SQL从入门到实战

学前须知 sqlzoo数据介绍 world nobel covid ge game、goal、eteam teacher、dept movie、casting、actor 基础语句 select&from SELECT from WORLD Tutorial - SQLZoo 基础查询select单列&多列&所有列&别名应用 例题一 SELECT name, continent, population …...

Redis源码阅读-源码阅读方式

Redis源码下载 首先通过地址&#xff08;https://github.com/redis/redis&#xff09;下载redis的源码。redis的源码版本&#xff0c;这里可以选择合适的查看&#xff0c;这里选择的是redis 5.x版本的源码。 Redis源码查看方式 这里可以选择合适的C开发工具&#xff0c;打开…...

若依框架简介

若依&#xff08;RuoYi&#xff09;框架是一个基于Java语言的后台管理系统快速开发框架&#xff0c;它结合了多种前端和后端技术&#xff0c;提供了高效的开发工具。以下是对若依框架的详细解析&#xff1a; 一、技术架构 后端&#xff1a;若依框架后端采用了Spring Boot、My…...

MOE怎样划分不同专家:K-Means聚类算法来实现将神经元特征聚类划分

MOE怎样划分不同专家:K-Means聚类算法来实现将神经元特征聚类划分 目录 MOE怎样划分不同专家:K-Means聚类算法来实现将神经元特征聚类划分MOE划分不同专家的方法K-Means聚类算法来实现将神经元特征聚类划分成不同专家(行或者列聚类)举例说明怎么聚类,最后神经网络怎么保存M…...

为 CentOS7 虚拟机添加第二块网卡

为 CentOS7 虚拟机添加第二块网卡 目录 为 CentOS7 虚拟机添加第二块网卡一、在虚拟中添加网卡二、网卡配置1、查看新增的网卡信息2、创建网卡配置文件 一、在虚拟中添加网卡 1、右击虚拟机&#xff0c;在弹出的菜单中选择【设置】&#xff0c;弹出如下图所示的【虚拟机设置】…...

30天开发操作系统 第 12 天 -- 定时器

前言 定时器(Timer)对于操作系统非常重要。它在原理上却很简单&#xff0c;只是每隔一段时间(比如0.01秒)就发送一个中断信号给CPU。幸亏有了定时器&#xff0c;CPU才不用辛苦地去计量时间。……如果没有定时器会怎么样呢?让我们想象一下吧。 假如CPU看不到定时器而仍想计量时…...

雷达的分类

雷达是一种利用电磁波进行探测和定位的设备&#xff0c;其分类方式多种多样&#xff0c;以下是按照不同标准对雷达进行的分类&#xff1a; 一、按功能分类 警戒雷达&#xff1a;用于搜索、监视和识别空中、海面或地面的目标&#xff0c;为防御系统提供早期预警。引导雷达&…...

Ubuntu桌面管理环境: GDM3,KDM,LightDM

介绍 Ubuntu是一个广受欢迎的Linux操作系统&#xff0c;拥有强大而多样化的桌面管理环境。其中三个常用的桌面管理环境是GDM3&#xff0c;KDM和LightDM。本篇博客将介绍这三个桌面管理环境的特点和功能。 GDM3 (GNOME Display Manager) GDM3是默认的桌面管理环境&#xff0c…...

使用Llama 3.1创建合成数据集以调优你的大型语言模型

使用Llama 3.1创建合成数据集以调优你的大型语言模型 在数据驱动的人工智能领域&#xff0c;数据是核心资产。开发高质量数据集既复杂又昂贵&#xff0c;因此很多实验室和开发者选择使用合成数据集。本文将介绍如何利用大型语言模型Llama 3.1 405B创建合成数据集&#xff0c;并…...

js可不使用document直接根据id获取id元素

今天在用原生js写demo的时候发现一个有意思的小现象&#xff0c;那就是可以直接根据元素的id去获取对应的元素。 起先是我定义了四个btn&#xff0c;每个btn都是根据getElementById来获取元素&#xff0c;然后给元素绑定事件&#xff0c;在调试的时候都挺好&#xff0c;到了后…...

【竞技宝】CS2:HLTV2024职业选手排名TOP8-broky

北京时间2025年1月7日,HLTV年度选手排名正在持续公布中,今日凌晨正式公布了今年的TOP8为FAZE战队的broky。 选手简介 broky是一位来自拉脱维亚的职业CS选手,现年23岁。2018年7月,broky获得了FPL资格,连续几季在榜上前5。他的首次赛场留名是跟随拉脱维亚本土战队Wolsung出征BES…...

Apache Paimon-实时数据湖

一、Apache Paimon是什么? Flink社区希望能够将 Flink 的 Streaming 实时计算能力和 Lakehouse 新架构优势进一步结合&#xff0c;推出新一代的 Streaming Lakehouse 技术&#xff0c;促进数据在数据湖上真正实时流动起来&#xff0c;并为用户提供实时离线一体化的开发体验。 …...

hpm使用笔记————使用usb作为从机接收来自上位机的数据然后通过spi主机发送给spi从机

历程整合 环境要求任务需求任务实现代码实现任务测试功能测试 结束 环境 hpm_sdk v 1.7.0ses v8.10 要求 例程demo USB-CDC 作为从机接收&#xff0c;然后把接收到的数据转发给SPI&#xff0c;SPI传输出去 任务需求 USB使用cherry协议栈进行开发 作为device设备&#xff08;…...

数据结构(查找算法)

1. 查找的概念 在一堆数据中&#xff0c;找到我们想要的那个数据&#xff0c;就是查找&#xff0c;也称为搜索&#xff0c;很容易想到&#xff0c;查找算法的优劣&#xff0c;取决于两个因素&#xff1a; 数据本身存储的特点查找算法本身的特点 比如&#xff0c;如果数据存储…...

private前端常见算法

1.数组 合并两个有序数组&#xff08;简单-5&#xff09; https://leetcode.cn/problems/merge-sorted-array/description/?envTypestudy-plan-v2&envIdtop-interview-150 移除元素&#xff08;简单-4&#xff09; https://leetcode.cn/problems/remove-element/descr…...

Go语言之十条命令(The Ten Commands of Go Language)

Go语言之十条命令 Go语言简介 Go语言&#xff08;又称Golang&#xff09;‌是由Google开发的一种开源编程语言&#xff0c;首次公开发布于2009年。Go语言旨在提供简洁、高效、可靠的软件开发解决方案&#xff0c;特别强调并发编程和系统编程‌。 Go语言的基本特征 ‌静态强类…...

Residency 与 Internship 的区别及用法解析

Residency 与 Internship 的区别及用法解析 在英文中&#xff0c;“residency” 和 “internship” 都与职业培训相关&#xff0c;但它们的使用场景和具体含义存在显著差异。本文将详细解析这两个词的区别&#xff0c;以及它们在不同语境下的应用。 Residency 的定义及使用场景…...

成品电池综合测试仪:电子设备性能与安全的守护者|鑫达能

在现代科技和工业领域&#xff0c;电池作为能量储存和转换的关键组件&#xff0c;其性能的稳定性和可靠性至关重要。为了确保电池在各种应用场景中都能发挥最佳性能&#xff0c;成品电池综合测试仪应运而生。这一设备不仅能够对电池的各项性能指标进行全面、准确的检测&#xf…...

Taro地图组件和小程序定位

在 Taro 中使用腾讯地图 1.首先在项目配置文件 project.config.json 中添加权限&#xff1a; {"permission": {"scope.userLocation": {"desc": "你的位置信息将用于小程序位置接口的效果展示"}} }2.在 app.config.ts 中配置&#x…...

深入了解 SSL/TLS 协议及其工作原理

深入了解 SSL/TLS 协议及其工作原理 一. 什么是 SSL/TLS?二. SSL/TLS 握手过程三. SSL/TLS 数据加密与传输四. 总结 点个免费的赞和关注&#xff0c;有错误的地方请指出&#xff0c;看个人主页有惊喜。 作者&#xff1a;神的孩子都在歌唱 一. 什么是 SSL/TLS? 安全套接层&am…...