六、Go语言快速入门之数组和切片
文章目录
- 数组和切片
- 数组
- :one: 数组初始化
- :two: 数组的遍历
- :three: 多维数组
- :four: 将数组传递给函数
- 切片(Slice)
- :one: 切片的初始化
- :star: `new`和`make`区别
- :two: 切片的使用
- :three: 将切片传递给函数
- :four: 多维切片
- :four: Bytes包
- :four: 切片和垃圾回收
📅 2024年4月28日
📦 使用版本为1.21.5
数组和切片
⭐️ 在go
语言中数组和切片看起来几乎一模一样,区别在于数组是不可变扩容的,切片是可变可伸缩(在Java
中想数组和列表(ArrayList
))
数组
⭐️ 在go
中数组只能是基本类型,不能是引用类型(在Java
中两者都可以)
⭐️ 由于数组是固定大小的,如果你知道了你要存放数据的长度,且以后不会有扩容了,就可以考虑使用数组
⭐️ Go
语言的数组是一种值类型,不是指针类型
1️⃣ 数组初始化
⭐️ 由于数组在声明后大小就不能变,声明大小时可以使用常量来替换
func main() {var a = 1;const b = 1;var aa [a]int; //报错a是变量var bb [b]int;
}
⭐️ 当然和其他语言一样它还可以声明并赋值,下标也是从0开始的,可以通过下标来范围和其他语言类似
func main() {const b = 3var bb = [b]int{1,2,3}println(bb[0])
}
⭐️ 可以通过len
来访问数组中元素的数量,还可以通过cap
来查看数组的容量
⭐️ 如果想要创建一个指针类型的数组就可以用到new
- 数值类型数组赋值,改变另外一个数组不会影响赋值的数组
func main() {a := [5]int{1, 2, 3, 4, 5}b := ab[2] = 100fmt.Println(a)fmt.Println(b)
}//输出
[1 2 3 4 5]
[1 2 100 4 5]
- 指针类型相反
func main() {a := new([5]int)b := ab[2] = 100fmt.Println(a)fmt.Println(b)
}//输出
&[0 0 100 0 0]
&[0 0 100 0 0]
⭐️ 还可以通过切割来访问数组的某一段数值,和其他语言差不多
arr[1:3]
2️⃣ 数组的遍历
⭐️ 可以使用for
和for-range
来遍历数组
func main() {a := []int{1, 2, 3, 4, 5}for i := 0; i <= len(a); i++ {fmt.Printf("%d ", i)}println()for i, v := range a {fmt.Printf("%d %d\n", i, v)}
}
3️⃣ 多维数组
⭐️ 想像成阵列就好了
func main() {var a [10][4]intfor i := 0; i < len(a); i++ {for j := 0; j < len(a[i]); j++ {a[i][j] = i + j}}
}
⭐️ 还可以使用for-range
func main() {var a [10][4]intfor row := range a {for column := range a[0] {a[row][column] = 1;}}
}
4️⃣ 将数组传递给函数
第一个大数组传递给函数会消耗很多内存,使用下面的方法可以避免:
- 可以像C语言那样使用数组的指
- 也可以使用切片(学到切片再说)
package mainimport "fmt"func main() {var a [10][4]intfuncName(&a)
}func funcName(a *[10][4]int) {for i := 0; i < len(a); i++ {for j := 0; j < len(a[i]); j++ {fmt.Printf("a[%d][%d] ", i, j)}}
}
切片(Slice)
⭐️ 切片在Go中使用的更加广泛,由于它可变成的特性,可以使用它来频繁的插入和删除元素
⭐️ 一个切片是对底层数组的一个连续片段的引用,因此它被视为引用类型。这种结构设计使得多个切片能够共享相同的底层数组内存,即使这些切片表达的是数组的不同部分。当通过一个切片对底层数组进行修改时,所有指向同一底层数组的其他切片都会看到这些更改。这是因为切片并没有复制底层数组的元素,而只是提供了一种访问和操作这些元素的方式,有点像java
数组和ArrayList
的关系,
⭐️ 一个切片由三个部分组成,指针、长度、容量,指针指向第一个切片元素对于的底层数组元素地址,但是并不一定就是数组的一个元素
⭐️ 优点 因为切片是引用,所以它们不需要使用额外的内存并且比使用数组更有效率,所以在 Go 代码中 切片
比数组更常用
1️⃣ 切片的初始化
⭐️ 切片的初始化和数组类似,但是切片可以使用make
关键字来创建,也推荐使用make
来创建切片,make
函数接收三个参数:类型,长度,容量;,容量一定是会大于或者等于长度的,就像一个桶子里面水的高度不会大于桶子的高度
⭐️ 可以直接通过一个数组来创建切片Slice
arr1[0:5]
表示此数组从0到5(不包含5)被切成了一个切片5就是此切片的len
如果是arr1[0:5:5]
前两个数和之前提到的一样,但是最后这个(5-0)就表示cap
func main() {arr1 := [10]int{1,2,3,4,5,6,7,8,9,10}var slice1 []int = arr1[0:5] //通过数组的切片创建fmt.Println(slice1)
}
⭐️ 多个切片如果表示同一个数组的片段,它们可以共享数据;因此一个切片和相关数组的其他切片是共享存
储的,相反,不同的数组总是代表不同的存储。数组实际上是切片的构建块
func main() {arr1 := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}var slice1 []int = arr1[0:5] //通过数组的切片创建var slice2 []int = arr1[0:5]slice2[0] = 100 //修改切片2的0下标元素fmt.Println(slice1[0]) //发现切片1的也修改了
}//输出:
100
此时如果你想要扩容,就可以使用切片的切片操作,来扩容
然后,当执行
slice1 = slice1[0:6]
时,Go 语言会检查新切片所需的容量是否超过了现有切片的容量。在这个例子中,新切片需要的容量是6,而现有切片的容量是5。由于6大于5,Go 语言会分配一个新的底层数组来容纳这6个元素,并将新切片的指针指向这个新数组。然后,它会复制原切片中的元素到新数组中,并更新新切片的长度和容量。因此,尽管最初的切片
slice1
的容量只有5,但是在执行slice1 = slice1[0:6]
之后,slice1
被重新分配了一个更大的底层数组,其容量至少为6,以容纳新的切片范围。这就是为什么slice1
可以扩展到0:6
的原因
func main() {arr1 := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}var slice1 []int = arr1[0:5] //通过数组的切片创建fmt.Println(slice1) //输出:[1 2 3 4 5]slice1 = slice1[0:6] //切片的切片操作扩容fmt.Println(slice1) //输出:[1 2 3 4 5 6]
}
⭐️ 通过var nums []int
这种方式声明的切片,默认值为nil
,所以不会为其分配内存,而在使用make
进行初始化时,建议预分配一个足够的容量,可以有效减少后续扩容的内存消耗
//源代码// make内置函数分配并初始化一个类型的对象
// slice、map或chan(仅限)和new一样,第一个参数是类型,而不是
/ /值。与new不同,make的返回值类型与its相同
//参数,而不是指针。结果的具体情况取决于
//类型:
//
// slice: size指定了长度。切片的容量为
//等于它的长度可以向提供第二个整数参数
//指定不同的容量;它必须不小于
/ /长度。例如,make([]int, 0, 10)会分配一个底层数组
//返回长度为0、容量为10的切片
//由底层数组支持。
// map:一个空的map被分配了足够的空间来容纳
//指定元素的数量在这种情况下,大小可以省略
//分配一个较小的起始长度。
// channel:使用指定的参数初始化channel的缓冲区
//缓存容量。如果为零,或大小省略,则通道为
/ /无缓冲的。
func make(t Type, size ...IntegerType) Type
⭐️ 你使用make
函数创建一个切片时,如果指定了长度(第二个参数),那么切片将会被初始化为该长度,并且每个元素都会被初始化为该类型对应的零值。对于整数类型(如int
),零值就是0。
func main() {var a = make([]int, 1, 10)println(a[0]) //输出0
}
⭐️ 切片的长度代表着切片中元素的个数,切片的容量代表着切片总共能装多少个元素,切片与数组最大的区别在于切片的容量会自动扩张,而数组不会
⭐️ 和数组一样也可以使用new
来创建数组
func main() {var a = make([]int, 10)var b = new([10]int)[0:10]fmt.Printf("%T", b)fmt.Printf("%T", a)
}
⭐️ new
和make
区别
-
new
(T) 为每个新的类型T
分配一片内存,初始化为 0 并且返回类型为*T
的内存地址:这种方法 返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体;它相当于 &T{} 。 -
make
(T) 返回一个类型为T
的初始值,它只适用于3种内建的引用类型:切片
、map
和channel
2️⃣ 切片的使用
⭐️ 切片的基本使用与数组完全一致,区别只是切片可以动态变化长度
⭐️ 通过append
来对切片实行操作
- 在尾部添加元素
func main() {var a = make([]int, 0, 0) //创建一个空切片a = append(a, 1, 2, 3, 4, 5, 6, 7) //添加元素fmt.Println(len(a), cap(a)) //输出内部元素个数和切片的容量
}//输出7,8
新
slice
预留的buffer
容量 大小是有一定规律的。 在golang1.18
版本更新之前网上大多数的文章都是这样描述slice
的扩容策略的: 当原slice
容量小于1024
的时候,新slice
容量变成原来的2
倍;原slice
容量超过1024
,新slice
容量变成原来的1.25
倍。 在1.18
版本更新之后,slice
的扩容策略变为了: 当原slice
容量(oldcap
)小于256
的时候,新slice
(newcap
)容量为原来的2倍;原slice
容量超过256,新slice
容量newcap
=oldcap
+(oldcap
+3*256)/4
- 在头部插入元素
⭐️ ...
操作符被称为扩展操作符(spread
operator
),用于将切片或数组展开为多个单独的参数。
func main() {var a = make([]int, 0, 0) //创建一个空切片a = append(a, 1, 2, 3, 4, 5, 6, 7) //添加元素a = append([]int{-1, 'a'}, a...) //这个a会转换成unicode代码中的值97fmt.Println(a) //输出数组 [-1 97 1 2 3 4 5 6 7]fmt.Println(len(a), cap(a)) //输出内部元素个数和切片的容量
}
- 从中间插入
1.a[:i+1]: 这部分表示从切片a的开始到索引i+1处的元素,即保留原始切片的前i+1个元素。
2.[]int{999,888}: 这是一个包含两个整数999和888的切片,这是要插入的元素。
3.a[i+1:]...: 这部分表示从切片a的索引i+1处开始到末尾的所有元素,采用...的方式表示这些元素将被展开并追加到前面的切片组合之后。
4.append(...):将前面提到的三个切片部分组合起来,并执行append操作,将所有元素添加到一起,最终生成一个新的切片。
5.a = ...: 将新生成的切片赋值回原始切片a,完成插入操作并修改原始切片。
通过这种方式,切片a在索引i处被扩展,其中插入了两个新的整数值999和888。func main() {i := 3var a = make([]int, 0, 0) //创建一个空切片a = append(a, 1, 2, 3, 4, 5, 6, 7) //添加元素a = append(a[:i+1], append([]int{999, 888}, a[i+1:]...)...) //使用i当索引,在索引中间开辟两个空间来插入来插入元素fmt.Println(a) //输出数组fmt.Println(len(a), cap(a)) //输出内部元素个数和切片的容量
}
- 删除元素
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
//从头部删除n个元素
nums = nums[n:]
fmt.Println(nums) //n=3 [4 5 6 7 8 9 10]//从尾部删除n给元素
nums = nums[:len(nums)-n]
fmt.Println(nums) //n=3 [1 2 3 4 5 6 7]//从中间指定下标删除
nums = append(nums[:i], nums[i+n:]...)
fmt.Println(nums)// i=2,n=3,[1 2 6 7 8 9 10]
- 将切片 b 的元素追加到切片 a 之后: a = append(a, b…)
- 复制切片 a 的元素到新的切片 b 上:
b = make([]T, len(a))
copy(b, a)- 删除位于索引 i 的元素: a = append(a[:i], a[i+1:]…)
- 切除切片 a 中从索引 i 至 j 位置的元素: a = append(a[:i], a[j:]…)
- 为切片 a 扩展 j 个元素长度: a = append(a, make([]T, j)…)
- 在索引 i 的位置插入元素 x: a = append(a[:i], append([]T{x}, a[i:]…)…)
- 在索引 i 的位置插入长度为 j 的新切片: a = append(a[:i], append(make([]T, j), a[i:]…)…)
- 在索引 i 的位置插入切片 b 的所有元素: a = append(a[:i], append(b, a[i:]…)…)
- 取出位于切片 a 最末尾的元素 x: x, a = a[len(a)-1], a[:len(a)-1]
- 将元素 x 追加到切片 a: a = append(a, x)
3️⃣ 将切片传递给函数
⭐️ 前面说过传递数组你可以使用切片来提高程序运行效率
⭐️ 如果你有一个函数需要对数组做操作,你可能总是需要把参数声明为切片。当你调用该函数时,把数组分
片,创建为一个切片引用并传递给该函数
var slice1 []type = arr1[:] 那么 slice1 就等于完整的 arr1 数组(所以这种表示方式是
arr1[0:len(arr1)] 的一种缩写)。另外一种表述方式是: slice1 = &arr1 。
arr1[2:] 和 arr1[2:len(arr1)] 相同,都包含了数组从第二个到最后的所有元素。
arr1[:3] 和 arr1[0:3] 相同,包含了从第一个到第三个元素(不包括第三个)
func main() {var arr = [6]int{1, 2, 3, 4, 5, 6}sum := sum(arr[:]) //数组的切片fmt.Println(sum)
}func sum(a []int) int {sum := 0for _, i := range a {sum += i}return sum
}
4️⃣ 多维切片
⭐️和数组一样,切片通常也是一维的,但是也可以由一维组合成高维。通过分片的分片(或者切片的数
组),长度可以任意动态变化,所以 Go 语言的多维切片可以任意切分。而且,内层的切片必须单独分配
(通过 make 函数)
func main() {slice := [][]int{{1, 2, 3}, {4, 5, 6}}// slice2 := make([][]int, 2,10) 通过makefmt.Println(slice)
}
4️⃣ Bytes包
⭐️ []bytes
这种切片类型很常见,包括使用的string
类型,它底层就是使用的它
⭐️ 他提供一个非常有用的Buffer
,它可以实现类似Java
的Stringbuilder
的功能
//源代码
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {buf []byte // contents are the bytes buf[off : len(buf)]off int // read at &buf[off], write at &buf[len(buf)]lastRead readOp // last read operation, so that Unread* can work correctly.
}
⭐️ 使用,感觉它没有Stringbuilder
好用,它不能使用那种流方法,只能另起一行或者是用循环输入
func main() {var buffer bytes.Bufferbuffer.WriteString("hello") //追加Stringbuffer.WriteString("world") //追加Stringstr := buffer.String() //获取Stringfmt.Println(str) //helloworld}
func main() {var buffer bytes.Bufferfor {var str stringfmt.Scanln(&str)buffer.WriteString(str) //追加Stringif str == "q" {break}}str := buffer.String() //获取Stringfmt.Println(str) //helloworld}
4️⃣ 切片和垃圾回收
⭐️ 切片的底层指向一个数组,该数组的实际体积可能要大于切片所定义的体积。只有在没有任何切片指向的
时候,底层的数组内层才会被释放,这种特性有时会导致程序占用多余的内存
相关文章:

六、Go语言快速入门之数组和切片
文章目录 数组和切片数组:one: 数组初始化:two: 数组的遍历:three: 多维数组:four: 将数组传递给函数 切片(Slice):one: 切片的初始化:star: new和make区别 :two: 切片的使用:three: 将切片传递给函数:four: 多维切片:four: Bytes包:four: 切片和垃圾回收 📅 2024年…...

Java:数组的定义和使用(万字解析)
目录 1. 数组的概念 2. 数组的基础知识 2.1 数组的创建 \1. 基础创建格式: \2. 类似C语言的创建格式: 【错误的创建(初始化)格式】 2.2 数组的数据类型 2.3 数组的初始化 —— 两种方式 \1.动态初始化:(完全默认初始化) \2. 静态初…...

密码学简要介绍
密码学是研究编制密码和破译密码的技术科学,它研究密码变化的客观规律,主要包括编码学和破译学两大部分。 一、定义与起源 定义:密码学是研究如何隐密地传递信息的学科,在现代特别指对信息以及其传输的数学性研究,常被…...

2024.11月最新智能问答AI创作系统源码,GPT4.0多模态模型+AI换脸+AI智能体GPTs应用+AI绘画(Midjourney)+详细搭建部署教程
一、前言 SparkAi创作系统是一款基于ChatGPT和Midjourney开发的智能问答和绘画系统,提供一站式 AI B/C 端解决方案,AI大模型提问、AI绘画、专业版AI视频生成、文档分析、多模态识图理解、TTS & 语音识别对话、AI换脸、支持AI智能体应用(…...

江协科技STM32学习- P34 I2C通信外设
🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝…...

Python 继承、多态、封装、抽象
面向对象编程(OOP)是 Python 中的一种重要编程范式,它通过类和对象来组织代码。OOP 的四个核心概念是继承(Inheritance)、多态(Polymorphism)、封装(Encapsulation)和数据…...

在.net下后台设置前台UEditor编辑器不可编辑
今天手下有个问:当用户填写提交后,再次显示提交页面时,该页面的UEditor编辑器需要设置成不可编辑,怎么实现? 可以用后台调用前台js的方式实现: 例如: 前台页面: <div style&qu…...

Flutter CustomScrollView 效果-顶栏透明与标签栏吸顶
CustomScrollView 效果 1. 关键组件 CustomScrollView, SliverOverlapAbsorber, SliverPersistentHeader 2. 关键内容 TLDR SliverOverlapAbsorber 包住 pinned为 true 的组件 可以被CustomScrollView 忽略高度。 以下的全部内容的都为了阐述上面这句话。初阶 Flutter 开发知…...

【新手入门软件测试--该如何分辨前后端问题及如何定位日志--前后端问题分辨与日志定位查询问题】
前后端问题分辨与日志定位查询 一、前端问题1. 页面无法加载2. 样式错乱3. API请求失败4. 数据格式错误5. 跨域请求问题 二、后端问题6. 表单验证失败7. 数据库连接失败8. 请求超时9. 权限问题10. JavaScript运行错误 三、日志查询的方法1. 查看日志文件2. 过滤关键字3. 实时查…...

【Java Web】DAO模式及单例模式(含代码示例)
文章目录 JDBC封装DAO模式实体类DAO接口DAO实现类数据源配置基础DAO类业务逻辑层 单例模式饿汉式懒汉式 JDBC封装 JDBC(Java Database Connectivity)封装是一种将 JDBC 的基本操作和常见的数据库访问逻辑封装成易于使用的工具类或框架的方法。这样做的目…...

深入探讨SEO分析技巧助力网站流量提升
内容概要 在当前的数字化时代,SEO分析的重要性不言而喻。它是提升网站流量的关键工具,帮助站长有效地优化网站内容和结构。通过系统的SEO分析,站长可以掌握用户搜索行为和需求,从而制定出更具针对性的内容策略。例如,…...

Chrome 130 版本开发者工具(DevTools)更新内容
Chrome 130 版本开发者工具(DevTools)更新内容 一、网络(Network)面板更新 1. 重新定义网络过滤器 网络面板获新增了一些过滤条件,这些过滤条件是根据反馈重新设计的,特定于类型的过滤条件保持不变&…...

深度学习基础知识-残差网络ResNet
目录 一、ResNet 的核心思想:残差学习(Residual Learning) 二、ResNet 的基本原理 三、ResNet 网络结构 1. 残差块(Residual Block) ResNet 的跳跃连接类型 2. 网络结构图示 四、ResNet 的特点和优势 五、ResNe…...

Linux云计算个人学习总结(二)
高级文件系统 一、RSYNC概述 1、作用:快速的文件复制工具(支持本地和远程),以及删除、查看等基本功能。 2、特点:支持实时(inotify、sersync)的增量备份工具3、模式:检查模式&#…...

Java入门(7)--网络编程
Java网络编程:构建网络应用的基石 🌐 🎯 掌握Java网络编程,打造强大的网络应用! 在上一篇文章中,我们探讨了Java的I/O操作和反射机制。今天,让我们深入学习Java网络编程,了解如何构建…...

[思考记录]思维局限,以为懂了
最近配合整理一些内容,找到较早期的某些产品设计资料在翻阅回顾。在这次回顾过程中,发现当时自己的理解存在很多局限。 以资源体系的设计为例,那时自认为已经“懂了”,对相关的概念、作用关系、组成及实现等都有一定的了解&#x…...

力扣题目解析--最长公共前缀
题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 ""。 示例 1: 输入:strs ["flower","flow","flight"] 输出:"fl"示例 2ÿ…...

不画饼——研究生学习和赚钱的平衡点
在现代社会中,年轻人面临着学习和赚钱之间的矛盾。尤其是在经济压力日益增大的背景下,如何在这两者之间找到合适的平衡点,成为了许多学生和职场新人面临的重要问题。本文将探讨在何种情况下应该听从老师的建议,专注于学习…...

华为实时视频使用FLV播放RTSP流
import flvjs from ‘flv.js’; 安装flv <video style"width:100%;height:100%;" ref"videoHWRef" ></video>// src 华为rtsp流 rtsp://admin:Huaweivideo10.10.8.151:554/xxx/trackID1// url 需要后端提供视频源地址playVideo() {if (fl…...

JAVA设计模式之【建造者模式】
1 定义 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 2 类图 产品类(Product):表示被创建的复杂…...

【jvm】为什么Xms和Xmx的值通常设置为相同的?
目录 1. 说明2. 避免性能开销3. 提升稳定性4. 简化配置5. 优化垃圾收集6. 获取参数6.1 代码示例6.2 结果示例 1. 说明 1.-Xms 和 -Xmx 参数分别用于设置堆内存的初始大小(最小值)和最大大小。2.在开发环境中,开发人员可能希望快速启动应用程…...

windows查看net网络监听端口命令和工具(ipconfig、netstat、tasklist、TCPView)
文章目录 使用命令提示符(CMD)查看网络连接和配置使用 netstat 命令查看监听端口查看特定的端口查看TCP监听端口tasklist查看对应进程ID的程序Get-NetTCPConnection 命令使用 TCPView工具使用命令提示符(CMD) 查看网络连接和配置 ipconfig :显示所有网络 适配器的当前 TC…...

JAVA-数据结构- 二叉搜索树
1.搜索树 前面我们已经使用C语言学习完了二叉树,懂得了一些二叉树的基本性质已经实现方法 https://mp.csdn.net/mp_blog/creation/editor/139572374,本文我们来一起进行二叉树的衍生-二叉搜索树 1.1 概念 二叉搜索树又称二叉排序树,它或者是…...

深入研究 RAG 流程中的关键组件
我们已经看到了整个RAG流程,并获得了第一手的实践经验,您可能会对RAG流程中一些组件的使用和目的存在很多疑惑,比如RunnablePassthrough。在本节中,我们将进一步了解这些关键组件。 RAG的核心模型思想是将一个复杂的任务分解为多…...

新手如何学习python并快速成为高手
英雄Python入门到精通链接:https://pan.quark.cn/s/57162ec366a9 学习Python作为新手,有以下几个步骤: 学习基本概念和语法:首先,你需要学习Python的基本概念和语法。可以通过在线教程、书籍或者视频教程来学习。了解…...

Linux历史命令history增加执行时间显示
Centos系统默认历史命令显示如下 为了更好的溯源,获取执行命令的准确时间,需要增加一些配置 设置环境变量 vim /etc/profile 在最下面添加以下环境配置 export HISTTIMEFORMAT"%Y-%m-%d %H:%M:%S " 立即刷新该环境变量 source /etc/pro…...

从 vue 源码看问题 — 你知道 Hook Event 吗?
前言 在之前的几篇文章中,都有提到 vue 中调用生命周期钩子时是通过 callHook() 方法进行调用的,比如在初始化篇章中调用 beforeCreate 和 created 生命周期钩子方式如下: 那么接下来一起来了解下到底什么是 Hook Event ? Hook Event 是什…...

信息安全工程师(68)可信计算技术与应用
前言 可信计算技术是一种计算机安全体系结构,旨在提高计算机系统在面临各种攻击和威胁时的安全性和保密性。 一、可信计算技术的定义与原理 可信计算技术通过包括硬件加密、受限访问以及计算机系统本身的完整性验证等技术手段,确保计算机系统在各种攻击和…...

每日OJ题_牛客_相差不超过k的最多数_滑动窗口_C++_Java
目录 牛客_相差不超过k的最多数_滑动窗口 题目解析 C代码 Java代码 牛客_相差不超过k的最多数_滑动窗口 相差不超过k的最多数_牛客题霸_牛客网 (nowcoder.com) 描述: 给定一个数组,选择一些数,要求选择的数中任意两数差的绝对值不超过 …...

来咯来咯webSocket
在项目总目录下 设置socketServe文件夹 里面创建下面两个文件 使用的时候需要开启 node webSocket.cjs var { Server } require(ws); var moment require(moment);const wss new Server({port: 8888 });let id 0; let onlineMemberList []; const defaultUser user;wss…...