【C++】:C++11详解 —— 右值引用

目录

左值和右值

左值的概念

 右值的概念

左值 vs 右值

左值引用 和 右值引用

左值引用

右值引用

左值引用 vs 右值引用

使用场景 

左值引用的使用场景

左值引用的短板 

右值引用的使用场景

1. 实现移动语义(资源高效转移)

2. 优化容器操作(如push_back、emplace_back)

3. 完美转发(Perfect Forwarding)


左值和右值

左值的概念

1、左值的定义

  • 左值(lvalue) 是表示 对象身份(identity) 的表达式,即它指向一个 明确且持久的内存位置

  • 术语中的 "l" 最初源自赋值操作中出现在 左边 的值(如 a = 5 中的 a),但左值并不仅限于赋值左侧,也可以出现在右侧。

 2、左值的关键特性

  • 可寻址性:左值对应具体的内存地址,可通过取地址操作符(&)获取其地址。
int x = 10;
int *p = &x; // x 是左值,可取其地址
  • 可修改性(除非被 const 限定):左值通常可被赋值,除非被声明为 const。 
int a = 5;
a = 20;      // 合法,a 是左值
const int b = 10;
b = 30;      // 非法,b 是 const 左值,不可修改
  • 持久性:左值代表的对象的生命周期超出其所在的表达式(如变量、数组元素等)。

3、代码示例 

int x = 5;        // x 是左值,5 是右值int y = x;        // x 作为右值使用(取其值)x = y + 10;       // x 是左值,y+10 的结果是右值int *p = &x;      // &x 合法(x 是左值)// &5;            // 非法,5 是右值,无地址const int c = 20; // c 是左值(可寻址),但不可修改// c = 30;        // 非法return 0;

 右值的概念

右值(rvalue)是编程语言(如C/C++)中的另一个核心概念,与左值(lvalue)相对。右值的核心特征是表示一个 临时的、不可寻址的值,通常用于计算或赋值操作中的右侧。

1、右值的定义

  • 右值(rvalue) 是表示 数据值(value) 的表达式,其核心是提供某个具体的值,而非持久的内存位置。

  • 术语中的 "r" 最初源自赋值操作中只能出现在 右侧 的值(如 a = 5 中的 5),但右值的含义在现代语言中更为复杂(尤其在C++中支持右值引用后)。

2、右值的关键特性

  • 不可寻址性:右值通常是临时的,没有明确的内存地址,不能通过取地址操作符(&)获取其地址。

int x = 5;
int y = x + 10;  // x + 10 是右值,无法写 &(x + 10)
  • 不可修改性:右值本身是只读的,不能直接修改。
int a = 5;
5 = a;       // 非法,5 是右值,不可赋值
a + 1 = 10;  // 非法,a + 1 是右值
  • 短暂的生命周期:右值通常是临时计算结果或字面量,生命周期仅限于当前表达式。

3、右值的常见形式

  • 字面量:如 5"hello"3.14

  • 临时对象:如函数返回的非引用类型值(int func() { return 42; }func() 是右值)。

  • 算术/逻辑表达式的结果:如 a + bx < y

  • 隐式转换生成的临时对象:如类型转换后的值(float(5))。

  • C++中的右值引用(C++11起):如 std::move(x) 返回的右值引用。

左值 vs 右值

特征左值右值
内存地址有明确地址(可寻址)无地址(不可寻址)
生命周期持久(超出当前表达式)短暂(表达式结束即销毁)
赋值操作可出现在赋值左侧(除非const)只能出现在右侧
典型示例变量、解引用指针字面量、临时结果、函数返回值

左值引用 和 右值引用

左值引用

左值引用是C++中用于为现有对象创建别名的一种机制,允许通过引用直接访问或修改原对象。

左值引用的定义

  • 左值引用(lvalue reference)是绑定到左值的引用,用 & 声明。

  • 必须初始化且无法重新绑定到其他对象。

  • 核心作用:避免对象拷贝、允许函数直接修改参数、实现更高效的操作。

基本语法与规则

类型& 引用名 = 左值;
  1. 必须初始化:引用声明时必须绑定到一个左值。

  2. 不可重新绑定:引用一旦初始化,无法更改指向的对象。

  3. 不可绑定到右值(除非使用 const):

int x = 10;
int& ref = x;  // ref是x的别名
ref = 20;      // 修改ref即修改x的值(x变为20)int& r1 = 5;         // 错误:右值不能绑定到非const左值引用
const int& r2 = 5;   // 正确:const左值引用可绑定到右值

右值引用

右值引用(rvalue reference)是C++11引入的核心特性,旨在支持 移动语义 和 完美转发,从而提升程序效率。

右值引用的定义

  • 右值引用 用 && 声明,专门绑定到 右值(临时对象、字面量等)。

  • 核心目的:允许资源(如动态内存、文件句柄)的高效转移,避免不必要的拷贝。

int&& rref = 42;           // 绑定到字面量(右值)
std::string&& s = func();  // 绑定到函数返回的临时对象

关键特性

  • 绑定到右值:只能绑定到即将销毁或临时的对象,不能直接绑定到左值(除非使用 std::move)。

int x = 10;
int&& r1 = x;              // 错误:x是左值
int&& r2 = std::move(x);   // 正确:std::move将左值转换为右值引用
  •  移动语义:通过移动构造函数和移动赋值运算符,直接“窃取”资源,避免深拷贝。
class MyVector 
{
public:// 移动构造函数MyVector(MyVector&& other) noexcept : data_(other.data_), size_(other.size_) {other.data_ = nullptr;  // 置空源对象指针other.size_ = 0;}// 移动赋值运算符MyVector& operator=(MyVector&& other) noexcept {if (this != &other) {delete[] data_;data_ = other.data_;size_ = other.size_;other.data_ = nullptr;other.size_ = 0;}return *this;}private:int* data_;size_t size_;
};
  • 完美转发:通过 std::forward 保持参数原始值类别(左值/右值),实现无损传递。 
template<typename T>
void wrapper(T&& arg) 
{// 保持arg的原始值类别(左值或右值)target_func(std::forward<T>(arg));
}

总结

右值引用的核心价值在于:

  1. 资源高效转移:通过移动语义减少拷贝开销。

  2. 完美转发:在泛型编程中精确传递参数。

  3. 现代C++基础:支持智能指针、容器优化等高级特性。

理解右值引用是掌握现代C++性能优化的关键步骤。

 

左值引用 vs 右值引用

特性左值引用 (&)右值引用 (&&)
绑定对象左值(具名对象、持久内存)右值(临时对象、即将销毁的值)
用途操作现有对象移动语义、资源高效转移
可修改性允许修改(除非 const通常用于“窃取”资源,避免拷贝
示例int& r = x;int&& r = std::move(x);

使用场景 

左值引用的使用场景

左值引用(&)在C++中用途广泛,核心目标是 避免不必要的拷贝、直接操作原对象

1. 函数参数传递(修改实参)

场景:函数需要修改外部变量,或传递大型对象(如容器、类实例)时避免拷贝。

// 交换两个变量的值
void swap(int& a, int& b) 
{int temp = a;a = b;b = temp;
}int main() 
{int x = 10, y = 20;swap(x, y);  // x=20, y=10(直接修改原对象)
}

2. 函数返回左值引用(返回可修改的别名)

场景:返回容器元素、类成员或链式赋值操作。

// 返回数组元素的引用,允许直接修改
int& getElement(int arr[], int index) 
{return arr[index];
}int main() 
{int arr[5] = {1, 2, 3, 4, 5};getElement(arr, 2) = 100;      // arr[2] = 100
}

3. 范围for循环修改容器元素

场景:遍历容器(如vectorarray)时直接修改元素。

std::vector<int> vec = {1, 2, 3, 4};
for (int& num : vec) 
{num *= 2;  // 直接修改vec中的元素
}
// vec变为 {2, 4, 6, 8}

4. 实现操作符重载

场景:重载赋值操作符或输入输出流操作符时,返回左值引用以支持链式操作。

class MyClass 
{
public:MyClass& operator=(const MyClass& other) {// 赋值逻辑return *this;  // 返回左值引用以支持连续赋值(a = b = c)}
};// 输出流重载
std::ostream& operator<<(std::ostream& os, const MyClass& obj) 
{os << obj.data;return os;  // 返回流引用以支持链式输出(cout << a << b)
}

5. const结合,接受右值或只读访问

场景:函数需要兼容左值和右值参数,或避免拷贝但禁止修改。

// 常量左值引用可绑定到右值
void print(const std::string& s) 
{std::cout << s;
}int main() 
{print("Hello");  // 接受右值(临时字符串)std::string str = "World";print(str);      // 接受左值
}

6. 实现链式调用(Fluent Interface)

场景:通过返回对象自身的引用,支持连续方法调用。

class StringBuilder 
{
private:std::string data;
public:StringBuilder& append(const std::string& s) {data += s;return *this;  // 返回自身引用}
};int main() 
{StringBuilder sb;sb.append("Hello").append(" ").append("World"); // 链式调用
}

7. 作为类成员,实现别名或代理模式

场景:类内部持有对其他对象的引用,避免拷贝。

class Window 
{
private:RenderContext& context;  // 引用外部渲染上下文
public:Window(RenderContext& ctx) : context(ctx) {}void draw() {context.render();  // 直接操作外部对象}
};

左值引用的短板 

1. 悬空引用(Dangling Reference)

问题:左值引用必须绑定到有效对象,但若引用的对象被销毁(如局部变量、临时对象),引用将指向无效内存,导致未定义行为(UB)。

总结就是出了函数,变量还是存在,就可以引用返回

int& createDanglingRef() 
{int x = 10;return x; // 错误:x在函数结束时销毁,返回的引用无效!
}int main() 
{int& ref = createDanglingRef(); // ref成为悬空引用std::cout << ref; // 未定义行为(可能崩溃或输出垃圾值)
}// 解决
// 1、避免返回局部变量的引用。
// 2、若需返回引用,确保其指向生命周期更长的对象(如静态变量、堆内存或参数传入的对象)。

2. 无法直接绑定到右值(除非使用 const

问题:非 const 左值引用不能绑定到右值(如字面量、临时对象),限制了函数参数的灵活性。

void modify(int& value) { value++; }int main() 
{modify(5); // 错误:5是右值,不能绑定到非const左值引用
}// 解决
// 1、使用 const 左值引用:允许绑定到右值,但禁止修改。
void readOnly(const int& value) { /* 只读操作 */ }
readOnly(5); // 合法// 2、重载函数或使用右值引用(C++11+)
void modify(int&& value) { /* 处理右值 */ }
modify(5); // 合法

3. 可能引发意外的数据修改

问题:若函数参数为非 const 左值引用,调用者可能未意识到传入的对象会被修改,导致逻辑错误。

void process(std::vector<int>& data) 
{data.clear(); // 清空外部数据(调用者可能未预料到)
}int main() 
{std::vector<int> myData = {1, 2, 3};process(myData); // myData被意外清空
}

4. 无法实现资源的高效转移

问题:左值引用只能操作现有对象,无法直接利用右值(临时对象)的资源,导致不必要的拷贝。

class HeavyObject 
{
public:HeavyObject(const HeavyObject& other) { /* 深拷贝(开销大)*/ }
};void useObject(HeavyObject& obj) { /* 操作obj */ }int main() 
{HeavyObject obj;useObject(obj);          // 合法,但无法优化临时对象的构造// useObject(HeavyObject()); // 错误:右值不能绑定到非const左值引用
}// 解决
// 1、结合右值引用(C++11+):实现移动语义,避免拷贝。
void useObject(HeavyObject&& obj) { /* 移动资源 */ }
useObject(HeavyObject()); // 合法,触发移动语义

6. 不适用于需要“移动”语义的场景

问题:左值引用无法直接支持资源的高效转移(如 std::vector 的重新分配内存),需依赖拷贝操作。

std::vector<std::string> oldData;
// 假设需要将oldData的内容转移到新容器
std::vector<std::string> newData = oldData; // 深拷贝(性能差)// 解决
// 1、使用右值引用和移动语义:
std::vector<std::string> newData = std::move(oldData); // 移动而非拷贝

总结与最佳实践

短板解决方案
悬空引用确保引用绑定到有效对象,避免返回局部变量引用。
无法绑定右值使用 const 左值引用或重载右值引用版本。
意外修改优先用 const 引用传递只读参数,明确函数副作用。
资源转移效率低结合右值引用实现移动语义。
生命周期管理复杂使用智能指针、明确所有权,避免跨作用域引用。

 

C++11提出右值引用就是为了解决左值引用的短板的,但解决方式并不是简单的将右值引用作为函数的返回值 

右值引用的使用场景

右值引用(&&)是C++11引入的核心特性,主要用于 移动语义 和 完美转发

1. 实现移动语义(资源高效转移)

场景:避免深拷贝大型对象(如容器、动态资源类),直接“窃取”资源所有权。

class DynamicArray 
{
private:int* data_;size_t size_;
public:// 移动构造函数(从临时对象“窃取”资源)DynamicArray(DynamicArray&& other) noexcept : data_(other.data_), size_(other.size_) {other.data_ = nullptr;  // 置空原对象,避免重复释放other.size_ = 0;}// 移动赋值运算符DynamicArray& operator=(DynamicArray&& other) noexcept {if (this != &other) {delete[] data_;      // 释放当前资源data_ = other.data_; // 接管资源size_ = other.size_;other.data_ = nullptr;other.size_ = 0;}return *this;}~DynamicArray() { delete[] data_; }
};int main() 
{DynamicArray a;DynamicArray b = std::move(a); // 触发移动构造函数,避免深拷贝
}

 

2. 优化容器操作(如push_backemplace_back

C++11标准出来之后,STL中的容器都增加了移动构造和移动赋值。

string 类

 vector 类

std::vector<std::string> vec;
// 添加临时对象(右值)
vec.push_back("Hello");       // C++11前:构造临时string,深拷贝到容器
vec.push_back(std::string("World")); // C++11后:移动临时对象,避免拷贝// 更高效的方式:直接构造元素(C++11的emplace_back)
vec.emplace_back("Hello");    // 直接在容器内存中构造,无拷贝或移动

3. 完美转发(Perfect Forwarding)

场景:完美转发(Perfect Forwarding)是C++11引入的核心机制,用于在泛型编程中精确传递参数的 值类别(左值/右值)和 类型,避免不必要的拷贝或类型损失。

为什么需要完美转发?

在多层函数调用中,若直接将参数传递给其他函数,参数的 值类别(左值/右值) 可能丢失,导致:

  1. 无法触发移动语义:右值被当作左值处理,引发不必要的拷贝。

  2. 重载匹配错误:目标函数可能无法正确调用左值或右值版本的重载。

template<typename T>
void relay(T arg) 
{target(arg); // 传递时arg始终是左值,右值属性丢失!
}void target(int& x) { std::cout << "左值版本\n"; }
void target(int&& x) { std::cout << "右值版本\n"; }int main() 
{int x = 5;relay(x);      // 期望调用左值版本relay(10);     // 期望调用右值版本,但实际调用左值版本!
}
// 输出始终为 左值版本,因为 arg 在 relay 函数内部是左值。

完美转发的实现

通过 通用引用(Universal Reference) 和 std::forward 实现:

  1. 通用引用(T&&):模板参数 T&& 可同时绑定到左值和右值,保留参数的原始值类别。

  2. std::forward<T>:根据 T 的原始类型,有条件地将参数转换为左值或右值引用。

注意:const T&& 不符合通用引用的语法形式:多了一个 const 修饰符。

 修正后的代码:

template<typename T>
void relay(T&& arg)           // 通用引用接受左值或右值
{target(std::forward<T>(arg)); // 完美转发
}void target(int& x) { std::cout << "左值版本\n"; }
void target(int&& x) { std::cout << "右值版本\n"; }int main() 
{int x = 5;relay(x);               // 调用左值版本relay(10);              // 调用右值版本relay(std::move(x));    // 调用右值版本
}

完美转发的核心机制

  1. 通用引用(T&&

    • 当模板参数为 T&& 且 T 需推导时,T&& 成为通用引用。

    • 可绑定到左值或右值,并保留原始值类别信息(通过 T 的类型推导)。

    传入参数类型T 推导结果arg 类型
    左值(int&int&int& && → int&
    右值(int&&intint&&
  2. std::forward<T> 的原理

    • 若 T 为左值引用(T = int&),std::forward<T> 返回左值引用。

    • 若 T 为非引用(如 int,表示原始参数是右值),std::forward<T> 返回右值引用。

    • 等效于:static_cast<T&&>(arg)

应用场景

1、容器操作(如 emplace_back
直接在容器内部构造元素,避免临时对象的拷贝或移动。

std::vector<std::string> vec;
vec.emplace_back("Hello"); // 直接在vec内存中构造string,无拷贝

完美转发 vs. std::move

特性std::forwardstd::move
用途保留参数原始值类别(左值/右值)强制转换为右值引用(用于移动)
条件性根据模板参数 T 决定是否转换无条件转换
典型场景泛型编程中的参数转发明确需要转移资源所有权的场景

 注意事项

 1、避免多次转发:同一参数被多次 std::forward 可能导致悬空引用(如移动后的对象被重复使用)。

template<typename T>
void relay(T&& arg) 
{target1(std::forward<T>(arg));target2(std::forward<T>(arg)); // 危险!arg可能已被移动
}

2、通用引用与重载的冲突:通用引用模板可能匹配过于广泛,导致与其他重载冲突。

template<typename T>
void foo(T&& arg) { /*...*/ }void foo(int x) { /*...*/ } // 重载可能被通用引用版本掩盖

3、const 限定符的处理:若参数有 const 修饰,需在转发时保留。

template<typename T>
void relay(const T&& arg)  // 注意:此处是右值引用,非通用引用!
{target(std::forward<const T>(arg));
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringMVC(四)Restful软件架构风格

目录 ​编辑 API接口设计的架构风格 一 Dao层实现&#xff08;处理数据库&#xff09; 二 Sercice层实现&#xff08;处理业务逻辑&#xff09; 三 Controller层&#xff08;处理http请求&#xff09; 四 补充知识点 1 PathVariable - 路径变量 2 CrossOrigin(Origins …

c++图论(二)之图的存储图解

在 C 中实现图的存储时&#xff0c;常用的方法包括 邻接矩阵&#xff08;Adjacency Matrix&#xff09;、邻接表&#xff08;Adjacency List&#xff09; 和 边列表&#xff08;Edge List&#xff09;。以下是具体实现方法、优缺点分析及代码示例&#xff1a; 1. 邻接矩阵&…

ABAP PDF预览

画个屏幕 PDF JPG TXT都可以参考预览&#xff0c;把二进制流传递给标准函数就行 *&---------------------------------------------------------------------* *& Report YDEMO2 *&---------------------------------------------------------------------* *&am…

Compose 的产生和原理

引言 compose 出现的目的&#xff1a; 重新定义android 上ui 的编写方式。为了提高android 原生ui开发效率。让android 的UI开发方式跟上时代。 正文 compose 是什么&#xff1f; 就是一套ui框架 和flutter 一样是一套ui框架 Flutter&#xff1a;跨平台开发趋势与企业应用的…

单口路由器多拨号ADSL实现方法

条件是多拨号场景&#xff0c;公司路由器接口不够用

H3C SecPath SysScan-AK 系列漏洞扫描系统

H3C SecPath SysScan-AK 系列是一款专业的漏洞扫描系统&#xff0c;旨在帮助组织和企业快速、准确地发现网络和系统中存在的安全漏洞。该系统具有以下特点&#xff1a; 1. 多样化的扫描能力&#xff1a;支持对各类网络设备、服务器、应用程序等进行漏洞扫描&#xff0c;能够全面…

[蓝桥杯 2023 省 B] 飞机降落

[蓝桥杯 2023 省 B] 飞机降落 题目描述 N N N 架飞机准备降落到某个只有一条跑道的机场。其中第 i i i 架飞机在 T i T_{i} Ti​ 时刻到达机场上空&#xff0c;到达时它的剩余油料还可以继续盘旋 D i D_{i} Di​ 个单位时间&#xff0c;即它最早可以于 T i T_{i} Ti​ 时刻…

Kafka详解——介绍与部署

1. 什么是 Kafka&#xff1f; Kafka 是一个分布式的消息队列系统&#xff0c;最初由 LinkedIn 开发&#xff0c;后来成为 Apache 开源项目。它的主要用途包括实时数据处理、日志收集、数据流管道构建等。Kafka 具备高吞吐量、可扩展性、持久性和容错性&#xff0c;广泛应用于大…

win10搭建opengl环境搭建并测试--输出立方体球体和碗型并在球体上贴图

参照本文档可以完成环境搭建和测试&#xff0c;如果想要快速完成环境的搭建可以获取本人的工程&#xff0c;包括所用到的工具链和测试工程源码获取&#xff08;非免费介意务下载&#xff09;&#xff1a;链接: https://pan.baidu.com/s/1H2ejbT7kLM9ore5MqyomgA 提取码: 8s1b …

TCP、UDP协议的应用、ServerSocket和Socket、DatagramSocket和DatagramPacket

DAY13.1 Java核心基础 TCP协议 TCP 协议是面向连接的运算层协议&#xff0c;比较复杂&#xff0c;应用程序在使用TCP协议之前必须建立连接&#xff0c;才能传输数据&#xff0c;数据传输完毕之后需要释放连接 就好比现实生活中的打电话&#xff0c;首先确保电话打通了才能进…

如何在 GoLand 中设置默认项目文件夹

在使用 GoLand 进行开发时&#xff0c;设置一个默认的项目文件夹可以大大提高工作效率。默认项目文件夹会在你打开或新建项目时自动预选&#xff0c;避免每次都需要手动导航到目标目录。本文将详细介绍如何在 GoLand 中设置默认项目文件夹。 步骤一&#xff1a;打开系统设置 …

SvelteKit 最新中文文档教程(5)—— 页面选项

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

Mac下Ollama安装全攻略:开启本地大模型之旅

文章目录 Mac下Ollama安装全攻略&#xff1a;开启本地大模型之旅一、Ollama 是什么功能特点优势应用场景 二、安装前准备&#xff08;一&#xff09;系统要求&#xff08;二&#xff09;硬件要求 三、下载安装包&#xff08;一&#xff09;官网下载&#xff08;二&#xff09;其…

华为营销流程落地方案:MTC=MTL+LTC

目录 简介 MTC流程 作者简介 简介 只讲最本质的底层逻辑&#xff0c;交付可落地的方案。 作为一个主打实践的产品老炮&#xff0c;接下来我将结合自己的经验&#xff0c; 以华为系的这套流程为基准&#xff0c; 将涉及业务层次的流程全部重构一套本地化、落地化的方案。 …

vscode使用ssh同时连接主机CentOS:user和ubuntu20.04:docker

主机为CentOS docker为Ubuntu20.04 两者可以使用一个vscode远程链接 1.使用已拉取好的Ubuntu镜像建立docker容器 2.进入容器内,下载一些关于ssh的安装包 apt-get install vim apt-get install openssh-client apt-get install openssh-server apt-get install ssh passwd …

NFS网络文件共享服务

文章目录 1. NFS工作原理1.1 挂载结构介绍1.2 NFS的工作原理 2. NFS服务安装2.1 NFS软件列表2.2 启动NFS相关服务2.3 NFS服务常见进程2.4 实战配置NFS服务器端 3. NFS服务配置3.1 在NFS Server端执行的操作3.1.1 查看部署环境3.1.2 启动rpcbind及NFS服务&#xff0c;然后加入开…

《多语言实时交流辅助系统前端的设计与实现》开题报告

个人主页&#xff1a;大数据蟒行探索者 目录 一、选题目的与意义 1.选题目的 2选题意义 2.1技术挑战与创新 2.2市场需求 2.3促进文化交流 2.4教育应用 2.5社会影响 二、研究现状与文献综述 1.研究现状 2.文献综述 2.1 前端技术的发展与应用 2.2 自然语言处理技术…

SpringCloud网关:Gateway路由配置与过滤器链

文章目录 引言一、Gateway基本架构二、路由配置方式2.1 配置文件方式2.2 Java代码方式 三、内置断言工厂四、内置过滤器工厂4.1 请求路径相关过滤器4.2 请求和响应头过滤器4.3 功能性过滤器 五、自定义过滤器5.1 自定义GatewayFilter5.2 自定义过滤器工厂 六、全局过滤器总结 引…

咖啡点单小程序毕业设计(JAVA+SpringBoot+微信小程序+完整源码+论文)

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着社会的快速发展和…

Excel(函数进阶篇):Vlookup函数进阶、TAKE嵌套SORE函数、SUBTOTAL函数、INDIRECT函数

目录 Vlookup函数返回多列结果Vlookup函数多条件匹配Vlookup函数部分匹配TAKE函数嵌套SORT函数&#xff0c;提取排序数据SUBTOTAL函数&#xff1a;制作动态报表SUBTOTAL函数&#xff1a;创建连续编号INDIRECT函数Vlookup跨多表抓取数据INDIRECT函数常见跨表的错误Vloopup函数联…