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

[C++ 11] 列表初始化:轻量级对象initializer_list

C++发展历史

C++11是C++语言的第二个主要版本,也是自C++98以来最重要的一次更新。它引入了大量的新特性,标准化了已有的实践,并极大地改进了C++程序员可用的抽象能力。在2011年8月12日被ISO正式采纳之前,人们一直使用“C++0x”这个名称,因为它原本预计会在2010年之前发布。然而,由于各种原因,直到2011年才最终确定。C++03与C++11之间间隔了8年,这是C++版本发布史上最长的一次。从那时起,C++社区每三年发布一次新标准,保持了更加稳定的更新节奏。

列表初始化

C++11引入了列表初始化(List Initialization),试图统一所有对象的初始化方式,使代码更加简洁和安全。然而,这也带来了一些细节和概念上的区别,可能会引起混淆。该章节将结合具体代码,深入讲解C++11中的列表初始化,与C++98进行对比,更清晰地理解这些概念。

C++98中的初始化方式

在C++98中,数组和聚合类型(如结构体)可以使用大括号{}进行初始化,但基本类型和自定义类对象通常不能直接使用{}初始化,需要使用构造函数或赋值操作。

数组和结构体的初始化

struct Point {int _x;int _y;
};int main() {// 数组初始化int a1[] = {1, 2, 3, 4, 5};int a2[5] = {0}; // 所有元素初始化为0// 结构体初始化Point p = {1, 2};return 0;
}

上述代码中,数组a1a2,结构体p都使用{}进行初始化,这是C++98所支持的。

基本类型和自定义类的初始化

在C++98中,基本类型的初始化不能使用{},需要使用赋值或构造函数。

int x = 2; // 赋值初始化

对于自定义类对象,需要定义构造函数,然后使用括号()进行初始化。

class Date {
public:Date(int year = 1, int month = 1, int day = 1): _year(year), _month(month), _day(day) {}private:int _year;int _month;int _day;
};int main() {Date d(2025, 1, 1); // 使用构造函数初始化return 0;
}

C++11中的列表初始化

C++11引入了列表初始化,使得几乎所有类型的对象都可以使用{}进行初始化,包括基本类型和自定义类对象。这种统一的初始化方式带来了代码简洁性和安全性的提升。

基本类型的列表初始化

int x1 = {2}; // 列表初始化
int x2 = 2;   // 传统赋值初始化
int x3{2};    // 省略等号的列表初始化
  • 区别x1x3使用了列表初始化,x2使用了传统的赋值初始化。
  • 优势:列表初始化可以防止窄化转换。例如,int x = {2.5};会编译错误,防止精度丢失。

自定义类型的列表初始化

Date d1 = {2025, 1, 1};
Date d20(2025, 1, 1);
const Date& d2 = {2024, 7, 25};
Date d3 = {2025};
Date d4 = 2025;
Date d6{2024, 7, 25};
const Date& d7{2024, 7, 25};
  • Date d1 = {2025, 1, 1};:使用列表初始化,按照语义应该是先构造一个临时的Date对象,然后调用拷贝构造函数复制给d1。但是,编译器会进行优化,直接构造d1,避免了拷贝构造。
  • const Date& d2 = {2024, 7, 25};:引用一个临时的Date对象,该对象由列表初始化创建。
  • Date d3 = {2025};:当只有一个参数时,列表初始化也可以使用。
  • Date d4 = 2025;:C++98中允许的隐式类型转换,调用Date(int, int, int)构造函数,剩余参数使用默认值。
  • 省略等号的初始化Date d6{2024, 7, 25};const Date& d7{2024, 7, 25};

结构体的列表初始化

struct Point {int _x;int _y;
};int main() {Point p1 = {1, 2}; // C++98风格Point p2{3, 4};    // C++11,省略等号return 0;
}

容器的列表初始化

vector<Date> v;
v.push_back(d1);
v.push_back(Date(2025, 1, 1));
v.push_back({2025, 1, 1}); // 使用列表初始化vector<int> v1 = {1, 2, 3, 4};
vector<int> v2 = {10, 20, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1};
const vector<int>& v4 = {10, 20, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1};vector<int> v3({10, 20, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1});
  • v.push_back({2025, 1, 1});:直接使用列表初始化创建一个Date对象,并插入到向量v中。
  • 容器的列表初始化v1v2v4v3都使用了列表初始化,其中v3显式地调用了构造函数。
std::initializer_list的使用
initializer_list<int> il1 = {10, 20, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1};
  • std::initializer_list是一个轻量级的只读容器,用于保存初始化列表中的元素。
  • 容器类(如vector)的构造函数和赋值运算符都增加了接受std::initializer_list的版本,因此可以直接使用{}进行初始化。
map的列表初始化和插入
map<string, string> dict;
dict.insert({"xxx", "yyyy"}); // 使用列表初始化的 pairmap<string, string> dict2 = {{"xxx", "yyyy"}, {"sort", "zzzz"}};
  • dict.insert({"xxx", "yyyy"});{"xxx", "yyyy"}会被隐式转换为std::pair<const string, string>,然后插入到dict中。
  • dict2的初始化:直接使用列表初始化,将多个键值对插入到map中。

std::initializer_list原理和作用

C++11引入了std::initializer_list,使得初始化容器和自定义类型的方式更加灵活和简洁。

背景

在C++98中,初始化数组和聚合类型(如结构体)可以使用大括号{},但对于容器和自定义类的初始化,尤其是当需要传入多个参数时,显得不够方便。例如,要初始化一个std::vector对象并赋予多个初始值,可能需要多次调用push_back,或者手动实现多个构造函数来支持不同数量的参数。

std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
// 或者手动实现多个构造函数来支持不同数量的参数

为了解决这个问题,C++11引入了std::initializer_list,提供了一种统一的方式来初始化容器和自定义类型。

std::initializer_list的原理

std::initializer_list是C++11标准库中的一个模板类,用于表示由大括号{}括起来的一系列元素。它允许我们使用列表初始化的方式为对象赋值,从而简化代码书写,提高可读性。

#include <initializer_list>std::initializer_list<int> il = {1, 2, 3};
内部实现

std::initializer_list内部包含了两个指针,分别指向初始化列表中第一个元素和最后一个元素的下一个位置。其实现通常如下:

template <class E>
class initializer_list {
public:// 类型定义typedef E        value_type;typedef const E& reference;typedef const E& const_reference;typedef size_t   size_type;typedef const E* iterator;typedef const E* const_iterator;// 构造函数initializer_list() noexcept : _array(0), _length(0) {}// 大小和开始、结束迭代器size_t size()  const noexcept { return _length; }const E* begin() const noexcept { return _array; }const E* end()   const noexcept { return _array + _length; }private:// 私有成员const E* _array;size_t   _length;
};
  • _array:指向存储元素的数组的指针。
  • _length:表示元素的数量。
特性
  • 只读容器std::initializer_list是一个轻量级的只读容器,不能修改其中的元素。
  • 自动推导类型:可以通过auto关键字自动推导类型。
  • 范围for循环:支持使用范围for循环遍历元素。

std::initializer_list的作用

初始化容器

C++11中的标准容器(如std::vectorstd::liststd::map等)都增加了接受std::initializer_list的构造函数和赋值运算符,使得容器可以方便地使用列表初始化。

#include <iostream>
#include <vector>
#include <map>
#include <string>int main() {// 初始化vectorstd::vector<int> v1 = {1, 2, 3, 4, 5};std::vector<int> v2{6, 7, 8, 9, 10}; // 省略等号// 初始化mapstd::map<std::string, std::string> dict = {{"apple", "苹果"},{"banana", "香蕉"}};// 输出vector内容for (auto val : v1) {std::cout << val << " ";}std::cout << std::endl;// 输出map内容for (const auto& pair : dict) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;
}

运行结果

1 2 3 4 5
apple: 苹果
banana: 香蕉
  • std::vector的列表初始化:通过{}直接传入初始值列表,调用了接受std::initializer_list的构造函数。然后作为initializer_list来构造容器。
  • std::map的列表初始化:使用{}传入键值对的列表,其中每个键值对也是使用{}初始化的std::pair对象,也就相当于initializer_list的嵌套构造。
自定义类型的初始化

除了标准容器,用户自定义的类也可以通过定义接受std::initializer_list的构造函数,来支持列表初始化。

#include <iostream>
#include <initializer_list>class MyClass {
public:MyClass(std::initializer_list<int> il) {for (auto it = il.begin(); it != il.end(); ++it) {data.push_back(*it);}}void print() const {for (auto val : data) {std::cout << val << " ";}std::cout << std::endl;}private:std::vector<int> data;
};int main() {MyClass obj = {1, 2, 3, 4, 5};obj.print(); // 输出:1 2 3 4 5return 0;
}
  • 接受std::initializer_list的构造函数:在自定义类MyClass中,定义了一个构造函数,接受std::initializer_list<int>类型的参数。
  • 使用列表初始化创建对象:在main函数中,直接使用{1, 2, 3, 4, 5}来初始化MyClass对象。
函数参数的初始化

std::initializer_list也可以作为函数的参数,方便地传递一组值。

#include <iostream>
#include <initializer_list>void printValues(std::initializer_list<int> il) {for (auto val : il) {std::cout << val << " ";}std::cout << std::endl;
}int main() {printValues({10, 20, 30, 40, 50});return 0;
}
10 20 30 40 50
  • 函数接受std::initializer_list参数printValues函数接受一个std::initializer_list<int>类型的参数。
  • 调用函数时传入列表:在调用printValues时,直接传入一个初始化列表{10, 20, 30, 40, 50},也可以作为构造函数或拷贝构造函数等的实参进行传入。

容器对std::initializer_list的支持

  1. 构造函数

标准容器都增加了接受std::initializer_list的构造函数。例如:

// vector的initializer_list构造函数
std::vector<int> v = {1, 2, 3, 4, 5};// map的initializer_list构造函数
std::map<std::string, int> m = {{"one", 1}, {"two", 2}};
  1. 赋值运算符

容器的赋值运算符也支持std::initializer_list,可以方便地重置容器的内容。

std::vector<int> v = {1, 2, 3};
v = {4, 5, 6}; // 重新赋值

示例代码:

#include <iostream>
#include <vector>
#include <map>int main() {// 使用initializer_list初始化vectorstd::vector<int> vec = {1, 2, 3, 4, 5};// 使用initializer_list赋值vectorvec = {6, 7, 8, 9, 10};// 输出vector内容for (auto val : vec) {std::cout << val << " ";}std::cout << std::endl;// 使用initializer_list初始化mapstd::map<std::string, int> mp = {{"apple", 1}, {"banana", 2}};// 输出map内容for (const auto& pair : mp) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;
}

运行结果:

6 7 8 9 10
apple: 1
banana: 2

相关文章:

[C++ 11] 列表初始化:轻量级对象initializer_list

C发展历史 C11是C语言的第二个主要版本&#xff0c;也是自C98以来最重要的一次更新。它引入了大量的新特性&#xff0c;标准化了已有的实践&#xff0c;并极大地改进了C程序员可用的抽象能力。在2011年8月12日被ISO正式采纳之前&#xff0c;人们一直使用“C0x”这个名称&#…...

【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (八):API说明(暂时完结,后续考虑将在线版mongoDB变为本地版)

本项目旨在学习如何快速使用 nodejs 开发后端api&#xff0c;并为以后开展其他项目的开启提供简易的后端模版。&#xff08;非后端工程师&#xff09; 由于文档是代码写完之后&#xff0c;为了记录项目中需要注意的技术点&#xff0c;因此文档的叙述方式并非开发顺序&#xff0…...

manictime整合两个数据库的数据

作用 老电脑崩溃了,有个1t.db&#xff0c; 新电脑有个3t.db 那么重装系统后就想整合起来用。 整合前文件大小 整合命令 .\mtdb.exe importtimelines -sdbpa ManicTimeCore-1t.db -dbpa ManicTimeCore-3t.db -tt ManicTime/ComputerUsage,ManicTime/Applications,ManicTime…...

Spring Boot植物健康系统:智慧农业的新趋势

6系统测试 6.1概念和意义 测试的定义&#xff1a;程序测试是为了发现错误而执行程序的过程。测试(Testing)的任务与目的可以描述为&#xff1a; 目的&#xff1a;发现程序的错误&#xff1b; 任务&#xff1a;通过在计算机上执行程序&#xff0c;暴露程序中潜在的错误。 另一个…...

(三)第一个Qt程序“Qt版本的HelloWorld”

一、随记 我们在学习编程语言的时候&#xff0c;各种讲解编程语言的书籍中通常都会以一个非常经典的“HelloWorld”程序展开详细讲解。程序虽然简短&#xff0c;但是“麻雀虽小&#xff0c;五脏俱全”&#xff0c;但是却非常适合用来熟悉程序结构、规范&#xff0c;快速形成对编…...

【Python知识】一个强大的数据分析库Pandas

文章目录 Pandas概述1. 安装 Pandas2. 基本数据结构3. 数据导入和导出4. 数据清洗5. 数据选择和过滤6. 数据聚合和摘要7. 数据合并和连接8. 数据透视表9. 时间序列分析10. 数据可视化 &#x1f4c8; 如何使用 Pandas 进行复杂的数据分析&#xff1f;1. 数据预处理2. 处理缺失值…...

10.26学习

1.整形的定义和输出 在C语言中&#xff0c;整形&#xff08;Integer&#xff09;是一种基本数据类型&#xff0c;用于存储整数。整形变量可以是正数、负数或零。在定义和输出整形变量时&#xff0c;需要注意以下几点&#xff1a; ①定义整形变量&#xff1a; 使用 int 关键字…...

CSS易漏知识

复杂选择器可以通过&#xff08;id的个数&#xff0c;class的个数&#xff0c;标签的个数&#xff09;的形式&#xff0c;计算权重。 如果我们需要将某个选择器的某条属性提升权重&#xff0c;可以在属性后面写!important&#xff1b;注意!importent要写在;前面 很多公司不允许…...

【10天速通Navigation2】(三) :Cartographer建图算法配置:从仿真到实车,从原理到实现

前言 往期内容&#xff1a; 第一期&#xff1a;【10天速通Navigation2】(一) 框架总览和概念解释第二期&#xff1a;【10天速通Navigation2】(二) &#xff1a;ROS2gazebo阿克曼小车模型搭建-gazebo_ackermann_drive等插件的配置和说明 本教材将贯穿nav2的全部内容&#xff0c…...

测试造数,excel转insert语句

目录 excel转sql的insert语句一、背景二、直接上代码 excel转sql的insert语句 一、背景 在实际测试工作中&#xff0c;需要频繁地进行测试造数并插入数据库验证&#xff0c;常规的手写sql语句过于浪费时间&#xff0c;为此简单写个脚本&#xff0c;通过excel来造数&#xff0…...

Python 应用可观测重磅上线:解决 LLM 应用落地的“最后一公里”问题

作者&#xff1a;彦鸿 背景 随着 LLM&#xff08;大语言模型&#xff09;技术的不断成熟和应用场景的不断拓展&#xff0c;越来越多的企业开始将 LLM 技术纳入自己的产品和服务中。LLM 在自然语言处理方面表现出令人印象深刻的能力。然而&#xff0c;其内部机制仍然不明确&am…...

从零开始:用Spring Boot搭建厨艺分享网站

2 相关技术 2.1 Spring Boot框架简介 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xff0c;Sprin…...

《2024中国泛娱乐出海洞察报告》解析,垂直且多元化方向发展!

随着以“社交”为代表的全球泛娱乐市场规模不断扩大以及用户需求不断细化&#xff0c;中国泛娱乐出海产品正朝着更加垂直化、多元化的方向发展。基于此&#xff0c;《2024中国泛娱乐出海洞察报告》深入剖析了中国泛娱乐行业出海进程以及各细分赛道出海现状及核心特征。针对中国…...

强化学习数学原理学习(一)

前言 总之开始学! 正文 先从一些concept开始吧,有一个脉络比较好 state 首先是就是状态和状态空间,显而易见,不多说了 action 同理,动作和动作空间 state transition 状态转换,不多说 policy 策略,不多说 reward 奖励,不多说 MDP(马尔科夫) 这里需要注意到就是这个是无…...

获 Sei 基金会投资的 MetaArena :掀起新一轮链上游戏革命

MetaArena 是一个综合性的 Web3 游戏开发和发布平台&#xff0c;集成了最先进的技术架构&#xff0c;包括 Unreal Engine 5.3、去中心化虚拟资产交易市场和分布式计算资源支持。平台不仅为开发者提供了高效的开发工具&#xff0c;还通过跨链功能和 AI 模块&#xff0c;极大简化…...

react-signature-canvas 实现画笔与橡皮擦功能

react-signature-canvas git 地址 代码示例 import React, { Component } from react import { createRoot } from react-dom/clientimport SignaturePad from ../../src/index.tsximport * as styles from ./styles.module.cssclass App extends Component {state { trimmed…...

004:ABBYY PDF Transformer安装教程

引言&#xff1a;本文主要讲解。 一、软件介绍 ABBYY PDF Transformer由ABBYY公司出品&#xff0c;属于一款家庭及商业都适用的PDF文档转换工具。它结合了ABBYY的OCR&#xff08;光学字符识别&#xff09;技术和Adobe PDF库技术&#xff0c;以确保能够便捷地处理任何类型的PDF…...

FlinkSQL之temporary join开发

在实时开发中&#xff0c;双流join获取目标对应时刻的属性时&#xff0c;经常使用temporary join。笔者在流量升级的实时迭代中&#xff0c;需要让流量日志精准的匹配上浏览时间里对应的商品属性&#xff0c;使用temporary join开发过程中踩坑不少&#xff0c;将一些经验沉淀在…...

第二十六节 直方图均衡化

图像直方图均衡化 图像直方图均衡化可以增强图像增强&#xff0c;对输入图像进行直方图均衡化处理&#xff0c;提升后续对象检测的准确率在Opencv人脸检测的代码演示中已经很常见了&#xff0c;此外对医学影像图像与卫星遥感图像也经常通过直方图均衡化来提升图像质量 Opencv…...

工单管理用什么工具好?8款推荐清单

本文推荐的8款项目工单管理系统有:1. PingCode; 2.Worktile; 3.Teambition; 4.致远OA; 5.TAPD; 6.Gitee; 7.Wrike; 8.Trello。 很多企业在处理项目工单时&#xff0c;依然依赖电子邮件、Excel表格&#xff0c;甚至是手动记录。这样做不仅效率低下&#xff0c;还容易导致工单遗漏…...

工地安全新突破:AI视频监控提升巡检与防护水平

在建筑工地和其他劳动密集型行业&#xff0c;工人的安全一直是管理工作的重中之重。为了确保工地的安全管理更加高效和智能化&#xff0c;AI视频监控卫士。通过人工智能技术&#xff0c;系统不仅能实时监控&#xff0c;还能自动识别工地现场的安全隐患&#xff0c;为工地管理者…...

World of Warcraft [CLASSIC][80][the Ulduar]

Ulduar 奥杜尔副本介绍 奥杜尔共计14个BOSS&#xff0c;通常说的10H就是10个苦难模式就是全通&#xff0c;9H就是除了【观察者奥尔加隆】&#xff0c;特别说明开启【观察者奥尔加隆】&#xff0c;是需要打掉困难模式4个守护者的。 所以人们经常说的类似“10H 观察者”、“10H…...

python实现数据库的增删改查功能,图形化版本

import tkinter from tkinter import * import psycopg2 from tkinter import messagebox#连接信息 t_conn{"dbname": "d1","user": "u1","password": "123qqq...A","port": "15400","h…...

pipeline开发笔记

pipeline开发笔记 jenkins常用插件Build Authorization Token Root配置GitLab的webhooks(钩子)配置构建触发器--示例 piblish over sshBlue OceanWorkspace Cleanup PluginGit插件PipelineLocalization: Chinese (Simplified) --中文显示Build Environment Plugin 显示构建过程…...

spark读取parquet文件

源码 parquet文件读取的入口是FileSourceScanExec&#xff0c;用parquet文件生成对应的RDD 非bucket文件所以走createNonBucketedReadRDD方法。 createNonBucketedReadRDD 过程&#xff1a; 确定文件分割参数 openCostInBytes4M 相关参数spark.sql.files.openCostInBytes4M…...

redis详细教程(1.String类型)

Redis 的 String 类型内部使用了一种叫做 SDS&#xff08;Simple Dynamic String&#xff09;的结构。SDS 的设计比传统的 C 语言字符串更加高效和安全&#xff0c;主要特点如下&#xff1a; 头部信息&#xff1a;SDS 的头部包含了一些元数据&#xff0c;比如字符串的长度、剩…...

用友U8接口-库存管理(7)

概括 本文的操作需要正确部署U8API主要讲述库存管理接口的使用&#xff0c;以产成品入库单作为说明&#xff0c;其他单据接口都是大同小异的&#xff01;许多时候先在ERP做个单&#xff0c;然后仿造ERP单据参数&#xff0c;构造接口JSON参数是不错的做法。 获取Token访问令牌…...

Spring Boot HikariCP数据库连接池入门

1. 概述 在我们的项目中&#xff0c;数据库连接池基本是必不可少的组件。在目前数据库连接池的选型中&#xff0c;主要是 Druid &#xff0c;为监控而生的数据库连接池。HikariCP &#xff0c;号称性能最好的数据库连接池。 至于怎么选择&#xff0c;两者都非常优秀&#x…...

Docker快速上手教程:MacOS系统【安装/配置/使用/原理】全链路速通

背景 最近换了个 Macbook Air M3, 写个人项目需要用到 Docker,配置过程有一点点坎坷,还是得记录下避免重蹈覆辙。 什么。为什么是买 Air 而不是 Pro Max? 因为码农的钱也是钱啊。 这里我不会先讲原理,我认为工程的事情都是先看到现象,有了概念的轮廓,才应该去研究原理,…...

【JavaSE】认识String类,了解,进阶到熟练掌握

#1024程序员节 | 征文# 下面就让博主带领大家一起解决心中关于String类的疑问吧~~~ 1.字符串构造&#xff1a; 第一种和第二种&#xff08;有一定的区别&#xff0c;在常量池上&#xff09; public static void main(String[] args) { // 使用常量串构造 String s1 "h…...

外贸b2b选品/谷歌seo搜索引擎

IE问题解决办法文章由小编整理发出&#xff0c;内容真实有效&#xff0c;欢迎提出您的意见IE系列文章由小编在互联网中整理并且发出&#xff0c;内容保障真实健康.IE浏览器怎么将网页保存为pdf文档很多小伙伴们都不清楚&#xff0c;接下来小编带来将网页保存为pdf文档的方法说明…...

大连住建委网站/qq群推广平台

第1章 Linux内核的简介1.1 UnixUnix强大的根本原因Unix很简洁&#xff1a;仅提供几百个系统调用并且有一个非常明确的设计目的&#xff1b;所有东西都被当做文件对待&#xff1a;提供一套系统调用接口—open()、read()、write()、lseek()和close()&#xff1b;用C语言编写而成&…...

怎么做阿里国际网站的数据分析/最新全国疫情消息

1. springMVC中controller的几种返回类型 Controller方法的返回值可以有以下几种&#xff1a; 1、返回ModelAndView 返回ModelAndView时最常见的一种返回结果。需要在方法结束的时候定义一个ModelAndView对象&#xff0c;并对Model和View分别进行设置。 2、返回String 1&a…...

网站制作过程/北京如何优化搜索引擎

现在支持GLSL和OpenGL跟步调试的只有Nvidia的Nsight&#xff0c;只支持Nvidia的显卡&#xff1b;其他的基本都是track&#xff0c;不支持GLSL的跟步调试&#xff0c;比如AMD的GPUPerfClient以及gDEBugger。还有AMD的GPU ShaderAnalyzer也非常的不错&#xff0c;能看到相应的GLS…...

怎么做网站写手/百度惠生活推广怎么收费

一&#xff0c;读书列表 1&#xff0c;<简明python教程>,电子版。。。python基础&#xff0c;在2月1日前看完并消化 2&#xff0c;<鸟哥的linux私房菜&#xff0d;基础篇>,电子版&#xff08;纸质的书&#xff0c;也太贵了&#xff0c;又厚&#xff09;&#xff0c…...

江苏专业做网站的公司/临沂百度联系方式

1.前言 最近无意中看到了阮一峰大佬的关于数字签名的一个翻译&#xff08;数字签名是什么&#xff1f;&#xff0c;该篇文章的精髓在于评论内容&#xff09;&#xff0c;觉得对数字签名突然没有那么迷茫了&#xff0c;所以决定做一个学习笔记&#xff0c;以便以后回来查阅。 …...