Redis Zset类型

news2025/1/11 2:36:41

Redis Zset类型

Zset(有序集合)它是集合的一种,不仅可以保存元素,还可以为每个元素关联一个 double 类型的分数(score),Redis 正是通过分数来为集合中的元素进行从小到大的排序。在 Zset 中,元素的值是唯一的,但分数(score)却可以重复。

有序集合:该有序集合显示了三国中的武将的武力

在这里插入图片描述

有序集合提供了获取指定分数和元素范围查找、计算成员排名等功能,合理地利用有序集合,可以帮助我们在实际开发中解决很多问题。

列表、集合、有序集合三者的异同点:

在这里插入图片描述

Zset命令

zadd

zadd 用于添加或者更新指定的元素以及关联的分数到 Zset 中,分数应该符合 double 类型,+inf/-inf作为正负极限也是合法的。

语法:

ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
  • key: 有序集合的键名。
  • score: 成员的分数。
  • member: 要添加到有序集合的成员。

相关选项

XX:仅仅用于更新已经存在的元素,不会添加新元素。

NX:仅用于添加新元素,不会更新已经存在的元素。

CH:默认情况下,ZADD 返回的是本次添加的元素个数,但指定这个选项之后,就会还包含本次更新的元素的个数。

INCR:此时命令类似 ZINCRBY 的效果,将元素的分数加上指定的分数。此时只能指定⼀个元素和分数。

时间复杂度:O(log(N))

返回值:本次添加成功的元素个数。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 1 "uno"
(integer) 1
redis> zadd myzset 2 "two" 3 "three"
(integer) 2
redis> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
redis> zadd myzset 10 one 20 two 30 three
(integer) 0
redis> zrange myzset 0 -1 withscores
1) "uno"
2) "1"
3) "one"
4) "10"
5) "two"
6) "20"
7) "three"
8) "30"
#CH选项-包含本次更新的元素的个数
redis> zadd myzset CH 100 one 200 two 300 three  
(integer) 3
redis> zrange myzset 0 -1 withscores
1) "uno"
2) "1"
3) "one"
4) "100"
5) "two"
6) "200"
7) "three"
8) "300"
redis> zadd myzset XX 1 one 2 two 3 three 4 four 5 five
(integer) 0
redis> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
redis> zadd myzset NX 100 one 200 two 300 three 400 four 500 five
(integer) 2
redis> zrange myzset 0 -1 withscores
# NX-只添加,不更新,只添加了 four 和 five
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
9) "four"
10) "400"
11) "five"
12) "500"
redis> zadd myzset INCR 10 one
"11"
redis> zrange myzset 0 -1 withscores
1) "uno"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
7) "one"
8) "11"
9) "four"
10) "400"
11) "five"
12) "500"
redis> zadd myzset -inf "negative infinity" +inf "positive infinity"
(integer) 2
redis> zrange myzset 0 -1 withscores
# -inf 无穷小 +inf 无穷大
1) "negative infinity"
2) "-inf"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
9) "one"
10) "11"
11) "four"
12) "400"
13) "five"
14) "500"
15) "positive infinity"
16) "inf"

zcard

zcard 用于获取⼀个 zset 的基数(cardinality),即 zset 中的元素个数。

语法:

ZCARD key

时间复杂度:O(1)

返回值:zset 内的元素个数。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zcard myzset
(integer) 2

zcount

返回分数在 min 和 max 之间的元素个数,默认情况下,min 和 max 都是包含的,可以通过 ( 排除。

语法:

ZCOUNT key min max

时间复杂度:O(log(N))

返回值:满⾜条件的元素列表个数。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zcount myzset -inf +inf
(integer) 3
redis> zcount myzset 1 3
(integer) 3
# 通过 (表示开区间
redis> zcount myzset (1 3
(integer) 2
redis> zcount myzset (1 (3
(integer) 1

zrange

返回指定区间里的元素,分数按照升序。带上 withscores 可以把分数也返回。

语法

ZRANGE key start stop [WITHSCORES]

此处的 [start, stop] 为下标构成的区间. 从 0 开始, ⽀持负数.

时间复杂度:O(log(N)+M)

返回值:区间内的元素列表。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
redis> zrange myzset 0 -1
1) "one"
2) "two"
3) "three"
redis> zrange myzset 2 3
1) "three"
redis> zrange myzset -2 -1
1) "two"
2) "three"

zrevrange

返回指定区间里的元素,分数按照降序。带上 withscores 可以把分数也返回。

备注:这个命令可能在 6.2.0 之后废弃,并且功能合并到 zrange 中。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zrevrange myzset 0 -1 withscores 
1) "three"
2) "3"
3) "two"
4) "2"
5) "one"
6) "1"
redis> zrevrange myzset 0 -1
1) "three"
2) "two"
3) "one"
redis> zrevrange myzset 2 3
1) "one"
redis> zrevrange myzset -2 -1
1) "two"
2) "one"

zrangebyscore

返回分数在 min 和 max 之间的元素,默认情况下,min 和 max 都是包含的,可以通过 ( 排除。

语法:

ZRANGEBYSCORE key min max [WITHSCORES]

时间复杂度:O(log(N)+M)

返回值:区间内的元素列表。

示例:

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zrangebyscore myzset -inf +inf
1) "one"
2) "two"
3) "three"
redis> zrangebyscore myzset 1 2
1) "one"
2) "two"
redis> zrangebyscore myzset (1 2
1) "two"                   
redis> zrangebyscore myzset (1 (2
(empty array)

zpopmax

删除并返回分数最高的 count 个元素。

语法:

ZPOPMAX key [count]

时间复杂度:O(log(N) * M)

返回值:分数和元素列表。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zpopmax myzset
1) "three"
2) "3"

bzpopmax

zpopmax 的阻塞版本。它会持续阻塞连接,直到有成员可以被弹出或达到超时时间。

语法:

BZPOPMAX key [key ...] timeout

timeout: 最大阻塞时间,以秒为单位,表示如果在此时间内没有元素弹出,命令将会超时。

时间复杂度:O(log(N))

返回值:元素列表,如果在超时之前没有可用的成员,命令将返回 null

示例

redis> bzpopmax set1 set2 10 set1 set2 10

这条命令将阻塞等待最多10秒钟,如果 set1set2 中有成员,它将返回其中分数最高的成员。如果超过10秒仍然没有可弹出的成员,命令将超时返回空响应。

zpopmin

删除并返回分数最低的 count 个元素。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zpopmin myzset
1) "one"
2) "1"

bzpopmin

zpopmin 的阻塞版本。

示例

redis> del zset1 zset2
(integer) 0
redis> zadd zset1 0 a 1 b 2 c
(integer) 3
redis> bzpopmin zset1 zset2 0
1) "zset1"
2) "a"
3) "0"

zrank

返回指定元素的排名,升序。排名有0开始

语法

ZRANK key member

时间复杂度:O(log(N))

返回值:排名。 没有则,返回nil

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zrank myzset "three"
(integer) 2
redis> zrank myzset "four"
(nil)

zrevrank

返回指定元素的排名,降序。排名有0开始

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zrevrank myzset "one"
(integer) 2
redis> zrevrank myzset "four"                          
(nil)

zscore

返回指定元素的分数。

语法

ZSCORE key member

时间复杂度:O(1)

返回值:分数。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zscore myzset "one"
"1"

zrem

删除指定的元素。

语法

ZREM key member [member ...]

时间复杂度:O(M*log(N))

返回值:本次操作删除的元素个数。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zrem myzset "two"
(integer) 1
redis> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "three"
4) "3"

zremrangebyrank

按照排序,升序删除指定范围的元素,左闭右闭。

语法

ZREMRANGEBYRANK key start stop

时间复杂度:O(log(N)+M)

返回值:本次操作删除的元素个数。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
redis> zremrangebyrank myzset 0 1
(integer) 2
redis> zrange myzset 0 -1 withscores
1) "three"
2) "3"

zremrangebyscore

按照分数删除指定范围的元素,左闭右闭。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zadd myzset 3 "three"
(integer) 1
# 表示 无穷小到1的范围,不包括2
redis> zremrangebyscore myzset -inf (2   
(integer) 1
redis> zrange myzset 0 -1 withscores
1) "two"
2) "2"
3) "three"
4) "3"

zincrby

为指定的元素的关联分数增加或减少指定的分数值。

语法

ZINCRBY key increment member
  • increment 为正数表示增加,负数表示减少

时间复杂度:O(log(N))

返回值:增加后元素的分数。

示例

redis> zadd myzset 1 "one"
(integer) 1
redis> zadd myzset 2 "two"
(integer) 1
redis> zincrby myzset 2 "one"
"3"
redis> zrange myzset 0 -1 withscores
1) "two"
2) "2"
3) "one"
4) "3"
redis> zincrby myzset -2 "one"    # -2 负数表示减少
"1"
redis> zrange myzset 0 -1 withscores
1) "one"
2) "1"
3) "two"
4) "2"

集合间操作

交集

有序集合的交集操作

在这里插入图片描述

zinterstore

zinterstore 求出给定有序集合中元素的交集并保存进目标有序集合中,在合并过程中以元素为单位进行合并,元 素对应的分数按照不同的聚合方式和权重得到新的分数。

语法

ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
  • destination:结果将存储在这个键中。
  • numkeys:要进行交集的输入键(有序集合)的数量。
  • key:一个有序集合的名称。
  • WEIGHTS:一个可选的关键字,后面跟着在交集操作中应用于有序集合的权重。
  • AGGREGATE:一个可选的关键字,指定如何聚合交集元素的分数。可以是 SUMMINMAX

时间复杂度:O(N×K)+O(M×log(M)) N 是输入的有序集合中, 最小的有序集合的元素个数; K 是输入了几个有序集合; M 是最终结果的有序集合的元素个数.

返回值:目标集合中的元素个数

示例

redis> zadd zset1 1 "one"
(integer) 1
redis> zadd zset1 2 "two"
(integer) 1
redis> zadd zset2 1 "one"
(integer) 1
redis> zadd zset2 2 "two"
(integer) 1
redis> zadd zset2 3 "three"
(integer) 1
# 交集时,zset1 的元素的分数会乘以 2,而 zset2 的元素的分数会乘以 3。
redis> zinterstore out 2 zset1 zset2 weights 2 3
(integer) 2
redis> zrange out 0 -1 withscores
1) "one"
2) "5"    # 1×2+1×3=2+3=5
3) "two"
4) "10"

并集

有序集合的并集操作

在这里插入图片描述

zunionstore

zunionstore 求出给定有序集合中元素的并集并保存进目标有序集合中,在合并过程中以元素为单位进行合并,元 素对应的分数按照不同的聚合方式和权重得到新的分数。

语法

ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
  • destination:结果将存储在这个键中,即新的有序集合的名称。
  • numkeys:要进行并集计算的输入键(有序集合)的数量。
  • key:一个有序集合的名称。
  • WEIGHTS:一个可选的关键字,后面跟着在并集操作中应用于有序集合的权重。
  • AGGREGATE:一个可选的关键字,指定如何聚合并集元素的分数。可以是 SUMMINMAX

时间复杂度:O(N)+O(M*log(M)) N 是输入的有序集合总的元素个数; M 是最终结果的有序集合的元素个数.

返回值:目标集合中的元素个数

示例

redis> zadd zset1 1 "one"
(integer) 1
redis> zadd zset1 2 "two"
(integer) 1
redis> zadd zset2 1 "one"
(integer) 1
redis> zadd zset2 2 "two"
(integer) 1
redis> zadd zset2 3 "three"
(integer) 1
# zset1 整体 * 2    zset2 整体 * 3
redis> zunionstore out 2 zset1 zset2 weights 2 3
(integer) 3
redis> zrange out 0 -1 withscores
1) "one"
2) "5"
3) "three"
4) "9"
5) "two"
6) "10"

内部编码

有序集合类型的内部编码有两种:

  • ziplist(压缩列表):当有序集合的元素个数小于 zset-max-ziplist-entries 配置(默认 128 个), 同时每个元素的值都小于 zset-max-ziplist-value 配置(默认 64 字节)时,Redis 会用 ziplist 来作为有序集合的内部实现,ziplist 可以有效减少内存的使用。
  • skiplist(跳表):当 ziplist 条件不满足时,有序集合会使用 skiplist 作为内部实现,因为此时 ziplist 的操作效率会下降。

1)当元素个数较少且每个元素较小时,内部编码为 ziplist:

127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3
(integer) 3
127.0.0.1:6379> object encoding zsetkey
"ziplist"

2)当元素个数超过 128 个,内部编码 skiplist:

127.0.0.1:6379> zadd zsetkey 50 e1 60 e2 30 e3 ... 省略 ... 82 e129
(integer) 129
127.0.0.1:6379> object encoding zsetkey
"skiplist"

3)当某个元素⼤于 64 字节时,内部编码 skiplist:

127.0.0.1:6379> zadd zsetkey 50 "one string bigger than 64 bytes ... 省略 ..."
(integer) 1
127.0.0.1:6379> object encoding zsetkey
"skiplist"

使用场景

有序集合比较典型的使⽤场景就是排行榜系统。例如常见的网站上的热榜信息,榜单的维度可能是多方面的:按照时间、按照阅读量、按照点赞量。本例中我们使用点赞数这个维度,维护每天的热榜:

1)添加用户赞数

例如用户 james 发布了一篇文章,并获得3个赞,可以使用有序集合的 zadd 和 zincrby 功能::

zadd user:ranking:2022-03-15 3 james

之后如果再获得赞,可以使用 zincrby:

zincrby user:ranking:2022-03-15 1 james

2)取消用户赞数

由于各种原因(例如用户注销、用户作弊等)需要将用户删除,此时需要将用户从榜单中删除掉,可以使用 zrem。例如删除成员 tom:

zrem user:ranking:2022-03-15 tom

3)展示获取赞数最多的 10 个用户

此功能使用 zrevrange 命令实现:

zrevrangebyrank user:ranking:2022-03-15 0 9

4)展示用户信息以及用户分数

此功能将用户名作为键后缀,将用户信息保存在哈希类型中,至于用户的分数和排名可以使用 zscore 和 zrank 来实现。

hgetall user:info:tom
zscore user:ranking:2022-03-15 mike
zrank user:ranking:2022-03-15 mike

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

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

相关文章

力扣LCR 166. 珠宝的最高价值(java 动态规划)

Problem: LCR 166. 珠宝的最高价值 文章目录 解题思路思路解题方法复杂度Code 解题思路 思路 改题目与本站64题实质上是一样的,该题目在64题的基础上将求取最小路径和改成了求取最大路径和。具体实现思路如下: 1.定义一个int类型的二维数组dp大小为给定…

跟着仙凡兄学习编译Telegram vs2022 2024.1.11编译成功

编译Telegram 本人花了两天,问官方作者终于编译成功Telegram 运行环境:win11 vs2022 参见学习视频:【telegram编译成功,编译遇到的各种问题】https://www.bilibili.com/video/BV11c411x7jm?vd_sourcedf2e51268cc7412cc3937cf3df2…

代码随想录第五十五天——判断子序列,不同的子序列

leetcode 392. 判断子序列 题目链接:判断子序列 确定dp数组及下标的含义 dp[i][j]:以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列长度为dp[i][j]确定递推公式 分为两种情况:s[i - 1] 与t[j - 1]相…

CMake入门教程【高级篇】qmake转cmake

😈「CSDN主页」:传送门 😈「Bilibil首页」:传送门 😈「动动你的小手」:点赞👍收藏⭐️评论📝 文章目录 1. 概述2.qmake与cmake的差异3. qmake示例4.qmake转cmake示例5.MOC、UIC和RCC…

k8s的存储卷之静态

存储卷----数据卷 容器内的目录和宿主机的目录进行挂载 容器在系统上的生命周期是短暂的,delete,k8s用控制创建的pod,delete相当于重启,容器的状态也会回复到初始状态 一旦回到初始状态,所有的后天编辑的文件都会消…

【Linux】Linux 系统编程——tree 命令

文章目录 1. 命令概述2. 命令格式3. 常用选项4. 相关描述4.1 tree 命令安装 5. 参考示例5.1 创建树形目录5.2 使用 tree 命令查看树形目录 1. 命令概述 tree 命令用于在命令行界面以树状图形式显示目录及其子目录的内容。这个命令递归地列出所有子目录,并可选择显示…

平时执行很快的SQL语句,为什么会突然卡一下?

InnoDB在处理更新语句的时候,只做了写日志这一个磁盘操作,这个日志叫作redo log(重做日志),在更新内存写完redo log后,就返回给客户端,本次更新成功。 把内存里的数据写入磁盘的过程&#xff0…

SpringBoot中使用SpringEvent业务解耦神器实现监听发布事件同步异步执行任务

场景 SpringBoot中使用单例模式ScheduledExecutorService实现异步多线程任务(若依源码学习): SpringBoot中使用单例模式ScheduledExecutorService实现异步多线程任务(若依源码学习)-CSDN博客 设计模式-观察者模式在Java中的使用示例-环境监测系统: 设…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)HttpResponse的定义和初始化 以及组织 HttpResponse 响应消息

一、HttpResponse的定义 1.定义状态码枚举 // 定义状态码枚举 enum HttpStatusCode {Unknown 0,OK 200,MovedPermanently 301,MovedTemporarily 302,BadRequest 400,NotFound 404 }; 2.HTTP 响应报文格式 这个数据块主要是分为四部分 第一部分是状态行第二部分是响应…

Godot之StringName解析

类描述 在Godot中,StringName是唯一字符串的内置类型。 StringName 是不可变的字符串,用于唯一名称的通用表示(也叫“字符串内嵌”)。值相同的两个 StringName 是同一个对象。进行比较时比普通 String 要快很多。 对于需要 Str…

时光总是催人老 time

文章目录 时光总是催人老 time语法示例更多信息 时光总是催人老 time … note:: 林花谢了春红,太匆匆。无奈朝来寒雨晚来风。 李煜《相见欢林花谢了春红》 Linux time命令的用途,在于测量指定命令消耗的时间。 最常用的在于大概评估一个程序的运行时…

APP流量变现——4项关键指标决定了APP混合变现的收入

APP流量变现的方式有很多种,主要的可以分为IAA(广告)收入、IAP(用户应用内付费)收入、订阅收入、单次买断收入。这里主要围绕当前流行的混合变现模式,即广告收入(IAA)应用内付费&…

vue3+vite开发生产环境区分

.env.development VITE_APP_TITLE本地.env.production VITE_APP_TITLE生产-ts文件中应用 console.log(import.meta.env.VITE_APP_TITLE)在html中应用,需要安装 html 模板插件 pnpm add vite-plugin-html -Dvite.config.ts中 import { createHtmlPlugin } from v…

鸿蒙原生应用再添新丁!万达 入局鸿蒙

鸿蒙原生应用再添新丁!万达 入局鸿蒙 来自 HarmonyOS 微博1月11日消息,#万达酒店及度假村启动鸿蒙原生应用及元服务开发# 作为具有中国特色的国牌服务酒店标杆之一,万达酒店及度假村Wanda 将带来全新的服务和交互方式,一步获取“…

【AI视野·今日Robot 机器人论文速览 第七十三期】Tue, 9 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Tue, 9 Jan 2024 Totally 40 papers 👉上期速览✈更多精彩请移步主页 Daily Robotics Papers Digital Twin for Autonomous Surface Vessels for Safe Maritime Navigation Authors Daniel Menges, Andreas Von Brandis, A…

基于ssm运动会管理系统的设计与实现 【附源码】

基于ssm运动会管理系统的设计与实现 【附源码】 🍅 作者主页 央顺技术团队 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 🍅 文末获取源码联系方式 📝 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuil…

Flashduty 案例分享 - 途游游戏

Flashduty 作为功能完备的事件OnCall中心,可以接入云上、云下不同监控系统,统一做告警降噪分派、认领升级、排班协同,已经得到众多先进企业的认可。我们采访了一些典型客户代表,了解他们的痛点、选型考虑和未来展望,集…

【排序算法】四、堆排序(C/C++)

「前言」文章内容是排序算法之堆排序的讲解。(所有文章已经分类好,放心食用) 「归属专栏」排序算法 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 堆排序1.1 原理1.2 堆的向下调整1.3 堆排序代码实现1.3 性质总结 堆排序 1.1 原理 概念介…

爬取去哪网旅游攻略信息

代码展现: import requests import parsel import csv import time f open(旅游去哪攻略.csv,modea,encodingutf-8,newline) csv_writer csv.writer(f) csv_writer.writerow([标题,浏览量,日期,天数,人物,人均价格,玩法]) for page in range(1,5):url fhttps://…

JS 函数

函数就是封装了一段可以被重复执行调用的代码块。目的:让大量代码重复利用 1、声明函数 方式一:利用函数关键字自定义函数(命名函数) function 函数名(){//函数体代码} function是声明函数的关键字&#…