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

类和对象实操之【日期类】

✨个人主页: Yohifo
🎉所属专栏: C++修行之路
🎊每篇一句: 图片来源

  • The pessimist complains about the wind; the optimist expects it to change; the realist adjusts the sails.

    • 悲观主义者抱怨风;乐观主义者期望它改变;现实主义者调整风帆。

    日期类


文章目录

  • 🗓️前言
  • 🗓️正文
    • 📆类的定义
      • 📅合法性检验
      • 📅判断闰年
      • 📅获取年份天数
      • 📅获取月份天数
    • 📆运算符重载
      • 📅判断等于
      • 📅判断小于
      • 📅复用至所有判断
      • 📅重载流插入、提取
    • 📆日期+=天数
      • 📅核心思想
      • 📅代码实现
    • 📆日期-日期
      • 📅核心思想
      • 📅代码实现
    • 📆自加、自减操作
      • 📅前置
      • 📅后置
    • 📆程序源码
  • 🗓️总结


🗓️前言

在学完类和对象相关知识后,需要一个程序来供我们练习、巩固知识点,日期类就是我们练习的首选程序,日期类实现简单且功能丰富,相信在完整地将日期类实现后,能对类和对象有更好的掌握及更深的理解

日历


🗓️正文

为了更符合工程标准,这里采用三个文件的方式实现程序

用于声明类和方法的 .h 头文件

Date.h

用于实现类和方法的 .cpp 源文件

Date.cpp

用于测试功能的 .cpp 源文件

test.cpp

工程框架

📆类的定义

先简单定义一下每个类中都有的默认成员函数

//当前位于文件 Date.h 中
#pragma once
#include<iostream>
using std::cout;	//采用部分展开的方式
using std::cin;//采用命名空间
namespace Yohifo
{class Date{public://构造函数,频繁使用且短小的代码直接在类的声明中实现,成为内联函数Date(int year = 2023, int month = 2, int day = 11):_year(year), _month(month), _day(day){}//拷贝构造函数Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}//赋值重载函数Date& operator=(const Date& d){if (this == &d)return *this;_year = d._year;_month = d._month;_day = d._day;return *this;}//析构函数~Date(){_year = 1970;_month = 2;_day = 11;}private:int _year;	//年、月、日int _month;int _day;};
}

📅合法性检验

首先编写第一个函数:合法性检验

检验标准

  • 年不能为0
  • 月在区间 [1, 12] 内,超过为非法
  • 根据年月推算出天数,天数不能操作规定天数,也不能 <= 0

注意:

  • 当前包括后续函数都是采取先在头文件 Date.h 的类中声明,再到 Date.cpp 实现的路径
  • 因历史原因导致的闰年变动这里不考虑,该程序实现的是理想情况下的闰年状态
  • 程序计算范围覆盖至公元前,限度为 [INT_MIN, INT_MAX]
#include"Date.h"using namespace Yohifo;	//全局展开命名空间//合法性检验
bool Date::check() const
{//年不能为0年if (_year == 0)return false;//月份区间 [1, 12]if (_month < 1 || _month > 12)return false;//天数要合理// getMonthDay 函数后续实现if (_day < 1 || _day > getMonthDay())return false;return true;
}

📅判断闰年

闰年二月多一天,因此需要特殊处理

闰年判断技巧: 四年一闰且百年不闰 或者 四百年一闰

//闰年判断
bool Date::checkLeapYear() const
{//按照技巧判断if (((_year % 4 == 0) && (_year % 100 != 0)) || (_year % 400 == 0))return true;elsereturn false;
}

📅获取年份天数

闰年多一天,为 366 ,非闰年为 365,判断返回即可

//获取年份天数
int Date::getYearDay() const
{//复用代码return (checkLeapYear() ? 366 : 365);
}

📅获取月份天数

根据当前年份和月份,判断当月有多少天

注意: 闰年的二月需要特殊处理

//获取月份天数
int Date::getMonthDay() const
{//非闰年情况下每个月天数,其中下标代表月份int arr[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };//如果为2月,且为闰年,直接返回 2月+1天if (_month == 2 && checkLeapYear())return arr[_month] + 1;elsereturn arr[_month];
}

📆运算符重载

前面学习了 operator 运算符重载,现在正好可以拿来练练手

📅判断等于

两个日期相等的前提是 都相等

//运算符重载
//判断等于
bool Date::operator==(const Date& d) const
{return ((_year == d._year) && (_month == d._month) && (_day == d._day));
}

📅判断小于

注意: 我们的运算顺序都是 左操作数右操作数,其中隐含的 this 指针默认为 左操作数

*this 小于 d 的逻辑

  • 首选判断年是否小于
  • 年相等,判断月是否小于
  • 年相等,月相等,判断天是否小于
//判断小于
bool Date::operator<(const Date& d) const
{if (_year < d._year)	//判断年return true;else if (_year == d._year && _month < d._month)	//判断月return true;else if (_year == d._year && _month == d._month && _day < d._day)	//判断天return true;elsereturn false;
}

📅复用至所有判断

善用代码复用,有了等于和小于,我们可以直接写出所有判断

//判断不等于
bool Date::operator!=(const Date& d) const
{return !(*this == d);	//等于,取反为不等于
}//判断小于等于
bool Date::operator<=(const Date& d) const
{//小于、等于成立一个即可return ((*this < d) || (*this == d));
}//判断大于
bool Date::operator>(const Date& d) const
{//即不小于,也不等于return (!(*this < d) && !(*this == d));
}//判断大于等于
bool Date::operator>=(const Date& d) const
{//大于或等于return ((*this > d) || (*this == d));
}

📅重载流插入、提取

coutcin 只能输出、输出内置类型,但如果我们对它进行改造一下,就能直接输出我们的自定义类型

注意:

  • cout 类型为 ostreamcin 类型为 istream
  • 要使得 coutcin 变为重载后的左操作数,此时的运算符重载就不能写在类内,因为在类中的函数默认 this 为第一个参数,即左操作数
  • 因此这两个函数比较特殊,需要写在外面,但同时又得访问类中的成员,此时就需要 友元函数
  • 两个函数都有返回值,返回的就是coutcin本身,避免出现 cout << d1 << d2 这种情况

此时可以利用合法性检验了

实现 operator>> 时,右操作数不能用 const 修饰

//在 Date.h 内
//新增几个局部展开
using std::ostream;
using std::istream;
using std::endl;namespace Yohifo
{class Date{//声明为类的友元函数friend std::ostream& operator<<(std::ostream& out, const Date& d2);friend std::istream& operator>>(std::istream& in, Date& d2);	//注意//……};//直接定义在头文件中,成为内联函数inline ostream& operator<<(ostream& out, const Date& d){//此时需要检验日期合法性if (Date(d).check() == false){out << "警告,当前日期非法!" << endl;out << "后续操作将会受到限制" << endl;}out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;}inline istream& operator>>(istream& in, Date& d){Date tmp;flag:cout << "请入日期,格式为:年 月 日" << endl;in >> tmp._year >> tmp._month >> tmp._day;//如果输入日期非法,就重新输入if (Date(tmp).check() == false){cout << "警告,当前日期非法!" << endl;cout << "日期输入失败,请尝试重新输入!" << endl;goto flag;}cout << "输入成功!" << endl;return in;}
}

有了这两个运算符重载后,我们就可以直接对自定义类型(日期类对象)直接进行输入输出操作了

Date d1;
cin >> d1;	//对自定义类型的输入
cout << d1;	//对自定义类型的输出

📆日期+=天数

下面涉及两个重要算法

  • 日期 += 天数
  • 日期 -= 天数

这里把 日期 += 天数 介绍清楚了,日期 -= 天数 就很好写了,就是倒着走

  • 有了 日期 += 天数 后,可以直接实现 日期 + 天数
  • 同理也可以实现 日期 - 天数

📅核心思想

注:此时实现的是 日期+=天数

进位思想:天数满了后进位到月份上,月份满后进位至年份上

进位

注意:

  • 每个月对应天数都需要计算,因为每个月都不同
  • 月份为12月时,再+就变成了下一年的一月
  • 假设为公元前,加至0年时,需要特殊处理为公元1年
  • += 操作返回的是左操作数本身,应对 (d1 += 10) = 20 这种情况

📅代码实现

//日期+=天数
Date& Date::operator+=(const int val)
{if (check() == false){cout << "警告,当前日期非法,无法进行操作" << endl;return *this;}//判断 val,避免恶意操作,如 d1 += -100if (val < 0){//此时需要调用 -=*this -= (-val);return *this;}//因为是 += 不需要创建临时对象//首先把天数全部加至 _day 上_day += val;//获取当前月份天数int monthDay = getMonthDay();//判断进位,直至 _day <= monthDaywhile (_day > monthDay){//此时大于,先把多余的天数减掉_day -= monthDay;//此时进位一个月++_month;//判断月份是否大于 12if (_month > 12){//此时需要进年++_year;//月份变为1月_month = 1;//判断是否为0年if (_year == 0)_year = 1;	//调整}//重新获取月份天数monthDay = getMonthDay();}//返回 *this 本身return *this;
}

有了这个函数后,我们就可以根据当前日期推算 N 天后的日期
运行结果

日期+天数 可以直接复用上面的代码,而 日期-=天数 将逻辑反过来就行了,这里不展示代码了,完整代码在文末的 gitee 仓库中


📆日期-日期

日期+日期无意义,但日期-日期有,可以计算两日期差值

日期相减有两种情况:

  • 左操作数小于右操作数,此时返回大于0的值
  • 左操作数大于右操作数,此时返回小于0的值

具体实现时也很好处理,直接用一个 flag 就行了

📅核心思想

先不管左右操作数大小,我们先找出较大操作数与较小操作数

通过较小操作数逐渐逼近较大操作数,其中经过的天数就是差值

步骤:

  • 先把日期对齐,即小操作数日期与大操作数日期平齐
  • 再把月份对齐
  • 最后再把年份对齐就行了
  • 随着步骤的深入,天数计算会越来越快的

除了这种方法外,我们还可以直接一天一天的加,直到相等,当然这种效率较低

📅代码实现

//日期 - 日期
const int Date::operator-(const Date& d) const
{if (check() == false || d.check() == false){cout << "警告,当前日期非法,无法进行操作!默认返回 0" << endl;return 0;}//假设右操作数为较大值Date max(d);Date min(*this);int flag = 1;//判断if (min > max){max = *this;min = d;flag = -1;}//小的向大的靠近int daySum = 0;//考虑天while (min._day != max._day){min += 1;daySum++;}//考虑月while (min._month != max._month){daySum += min.getMonthDay();min += min.getMonthDay();}//考虑年while (min._year != max._year){daySum += min.getYearDay();min._year++;}return daySum * flag;
}

这种方法(同轴转动)将会带来一定的性能提升(相对逐天相加来说)

方法相差 1k 年相差 1w 年相差 10w 年
同轴转动耗时 0 ms耗时 0 ms耗时 2 ms
逐天相加耗时 28 ms耗时 297 ms耗时 3142 ms

注:实际差异与电脑性能有关


📆自加、自减操作

自加操作实现很简单,不过需要注意编译器是如何区分两者的

占位参数

  • 因为前置与后置的运算符重载函数名一致,此时需要给运算符多加一个参数以区分,这是由编译器规定的合法行为,占位参数加在后置运算符重载中

📅前置

前置直接复用前面 += 的代码

前置操作是先进行自加或自减,再返回

//前置++
Date& Date::operator++()
{//直接复用*this += 1;return *this;
}//前置--
Date& Date::operator--()
{*this -= 1;return *this;
}

📅后置

此时需要借助 占位参数,当启用时,编译器会自动传参,并自动区分,占位参数 类型为 int

后置操作是先记录值,再进行自加或自减,返回之前记录的值

//后置++
const Date Date::operator++(int)
{//借助临时变量Date tmp(*this);*this += 1;return tmp;
}//后置--
const Date Date::operator--(int)
{Date tmp(*this);*this -= 1;return tmp;
}

特别注意: 对于自定义类型来说,在进行自加、自减操作时,最好采用前置,因为后置会发生拷贝构造行为,造成资源浪费


📆程序源码

完整的代码在这里 Gitee
动图


🗓️总结

以上就是关于日期类实现的全部内容了,涉及到了前面学的大部分知识,希望大家在看完后能把它独立敲一遍,加深理解

如果你觉得本文写的还不错的话,可以留下一个小小的赞👍,你的支持是我分享的最大动力!

如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正


星辰大海

相关文章推荐
类和对象合集系列
类和对象(下)
类和对象(上)
类和对象(中)

===============

C++入门必备
C++入门基础

感谢支持

相关文章:

类和对象实操之【日期类】

✨个人主页&#xff1a; Yohifo &#x1f389;所属专栏&#xff1a; C修行之路 &#x1f38a;每篇一句&#xff1a; 图片来源 The pessimist complains about the wind; the optimist expects it to change; the realist adjusts the sails. 悲观主义者抱怨风;乐观主义者期望它…...

微搭中如何实现弹性布局

我们在实际开发中经常可能会有一些社交的场景&#xff0c;比如开发一个类似朋友圈九宫格图片展示的功能。因为图片的数量不确定&#xff0c;所以需要实现图片的从左到右顺序排列。 在微搭中可以以可视化的方式设置样式。但是对于我们这类特殊需求&#xff0c;只用可视化设置显…...

九龙证券|外资强势出手!这只科创板百元股,被疯狂加仓

本周&#xff0c;北上资金净买入29.32亿元&#xff0c;连续第13周加仓A股。分商场看&#xff0c;北上资金加仓重点倾向于沪市的白马蓝筹股&#xff0c;沪股通取得50.34亿元&#xff0c;深股通则被净卖出21.02亿元。 食品饮料本周取得逾23亿元的增持&#xff0c;居职业首位&…...

51单片机最强模块化封装(4)

文章目录 前言一、创建key文件,添加key文件路径二、key文件编写三、模块化测试总结前言 本篇文章将为大家带来按键的模块化封装,这里使用到了三行按键使得我们的代码更加简便。 按键原理:独立按键 一、创建key文件,添加key文件路径 这里的操作就不过多解释了,大家自行看…...

五、Git本地仓库基本操作——分支管理

1. 什么是分支&#xff1f; master分支 我们在初始化git仓库的时候&#xff0c;会默认创建一个master分支&#xff0c;HEAD指针这时就会默认执行master分支。当我们在master分支提交&#xff08;commit&#xff09;了更新之后&#xff0c;master分支就会指向当前当前最新的co…...

vscode搭建python Django网站开发环境

这里使用pip安装的方式&#xff0c;打开命令行&#xff0c;输入执行&#xff1a; pip install django2.2这里选择安装2.2版本是因为是新的lts版本&#xff0c;长期支持稳定版。 接下来再安装pillow&#xff0c;Django底层一部分是基于pillow进行的。 pip install pillowpylint…...

【mybatis】实现分页查询

一 .使用原生分页器的实体类 1.1 java代码部分 方法多 不易书写 package cn.bdqn.entity;public class Page {private Integer pageIndex;//页码private Integer pageSize;//页大小 显示多少行数据private Integer totalCounts;//数据的总行数private Integer totalPages;//…...

CF1560D Make a Power of Two 题解

CF1560D Make a Power of Two 题解题目链接字面描述题面翻译题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示思路代码实现备注题目 链接 https://www.luogu.com.cn/problem/CF1560D 字面描述 题面翻译 给定一个整数 nnn。每次操作你可以做两件事情中的一件&am…...

C#开发的OpenRA的读取文件的函数

C#开发的OpenRA的读取文件的函数 在OpenRA游戏里,读取文件是必备的功能。 因为游戏大部分文件都是图片、动画、语音。 很久以前,我以为开发游戏的主要功能是在程序开发上, 其实游戏的大部分工作都不是在开发上,而是在美工方面。 因为游戏跟电影是一样,就是不断地展示场景,…...

SpringBoot结合XXL-JOB实现定时任务

Quartz的不足 Quartz 的不足&#xff1a;Quartz 作为开源任务调度中的佼佼者&#xff0c;是任务调度的首选。但是在集群环境中&#xff0c;Quartz采用API的方式对任务进行管理&#xff0c;这样存在以下问题&#xff1a; 通过调用API的方式操作任务&#xff0c;不人性化。需要…...

【Node.js】 创建web服务器

Node.js什么是客户端&#xff0c;什么是服务器服务器和普通电脑的区别什么是http模块导入http模块服务器相关概念创建web服务器的基本步骤req请求对象req响应对象解决中文乱码根据不同的url响应不同的html内容什么是客户端&#xff0c;什么是服务器 客户端在网络节点中&#x…...

基于go语言实现RestFul交互

一、RestFul 1.1 RestFul的介绍 RESTFUL&#xff08;Representational State Transfer&#xff09;是一种网络应用程序的设计风格和开发方式&#xff0c;基于HTTP或HTTPS&#xff0c;可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务接口的场景&…...

情感溢出:读《浣溪沙》

浣溪沙 谁念西风独自凉 作者 纳兰性德 谁念西风独自凉&#xff0c;萧萧黄叶闭疏窗&#xff0c;沉思往事立残阳。 被酒莫惊春睡重&#xff0c;赌书消得泼茶香&#xff0c;当时只道是寻常。 记得年轻时学这篇词&#xff0c;就是愣背&#xff0c;现在也就记得这句当时只道是寻常…...

深入解读.NET MAUI音乐播放器项目(一):概述与架构

系列文章将分步解读音乐播放器核心业务及代码&#xff1a; 深入解读.NET MAUI音乐播放器项目&#xff08;一&#xff09;&#xff1a;概述与架构深入解读.NET MAUI音乐播放器项目&#xff08;二&#xff09;&#xff1a;播放内核深入解读.NET MAUI音乐播放器项目&#xff08;三…...

【Python小游戏】某程序员将套圈游戏玩儿到了巅峰,好嗨哟~Pygame代码版《牛牛套圈》已上线,大人的套圈游戏太嗨了,小孩勿进。

前言 世上选择那么多。 关注栗子同学会是您最明智的选择哦。 所有文章完整的素材源码都在&#x1f447;&#x1f447; 粉丝白嫖源码福利&#xff0c;请移步至CSDN社区或文末公众hao即可免费。 “幸运牛牛套圈圈”套住欢乐&#xff0c;圈住幸福&#xff0c;等你来挑战&#xf…...

php的declare命令如何使用?

php中的declare结构用来设定一段代码的执行指令declare用于执行3个指令&#xff1a;ticks,encoding,strict_typesdeclare结构用于全局范围&#xff0c;影响到其后的所有代码&#xff08;但如果有declare结构的文件被其他文件包含&#xff0c;则对包含他的父文件不起作用&#x…...

嵌软工程师要掌握的硬件知识2:一文看懂什么开漏和推挽电路(open-drain / push-pull)

想了解开漏和推挽,就要先了解一下三极管和场效应管是什么,在其他章节有详细介绍,本文就不再进行赘述。 1 推挽(push pull)电路 1.1 理解什么是推挽电路 - 详细介绍 如图所示,Q3是个NPN型三极管,Q4是个PNP型三极管。 1)当Vin电压为正时,上面的N型三极管控制端有电…...

1.2.6存储结构-磁盘管理:单缓冲区与双缓冲区读取、流水线周期、计算流水线执行时间

1.2.6存储结构-磁盘管理&#xff1a;单缓冲区与双缓冲区读取、流水线周期、计算流水线执行时间流水线周期计算流水线执行时间微秒&#xff0c;时间单位&#xff0c;符号μs&#xff08;英语&#xff1a;microsecond &#xff09;&#xff0c;1微秒等于百万分之一秒&#xff08;…...

【pytest接口自动化测试】结合单元测试框架pytest+数据驱动模型+allure

api&#xff1a; 存储测试接口 conftest.py :设置前置操作 目前前置操作&#xff1a;1、获取token并传入headers&#xff0c;2、获取命令行参数给到环境变量,指定运行环境commmon&#xff1a;存储封装的公共方法 connect_mysql.py&#xff1a;连接数据库http_requests.py: 封装…...

展锐平台WIFI吞吐问题解决方案

同学,别退出呀,我可是全网最牛逼的 WIFI/BT/GPS/NFC分析博主,我写了上百篇文章,请点击下面了解本专栏,进入本博主主页看看再走呗,一定不会让你后悔的,记得一定要去看主页置顶文章哦。 一、Wi-Fi 吞吐验收标准 预置条件:屏蔽房;DUT 距离 AP 1m 左右;测试 AP 不加密;…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...