C++入门:引用
目录
一. 什么是引用
1.1 引用的概念
1.2 引用的定义
二. 引用的性质和用途
2.1 引用的三大主要性质
2.2 引用的主要应用
三. 引用的效率测试
3.1 传值调用和传引用调用的效率对比
3.2 值返回和引用返回的效率对比
四. 常引用
4.1 权限放大和权限缩小问题
4.2 跨数据类型的引用问题
五. 引用和指针的区别
一. 什么是引用
1.1 引用的概念
引用,通俗的讲,就是给已经存在的变量取一个别名,而不是创建一个新的变量。引用和被引用对象共同使用一块内存空间。
引用就好比一个人的大名和小名,大名和小名都是一个人。再比如,李逵外号黑旋风,叫李逵和黑旋风表示同一个人。
1.2 引用的定义
引用定义的语法格式:类型& 引用的名称 = 被引用实体
如,定义int a = 10,希望再定义一个引用b,来表示整形变量a的别名,语法为:int& b = a。演示代码1.1展示了引用的定义过程,对原变量a和引用b的其中任意一个赋值,都会使a和b的值均发生改变,这是因为a和b共用一块内存空间。
演示代码1.1:
int main()
{int a = 10;int& b = a; //b是a的引用(别名)printf("a = %d, b = %d\n", a, b); //10,10a = 20; //对a赋值,同时改变a和bprintf("a = %d, b = %d\n", a, b); //20,20b = 30; //对b赋值,同时改变a和bprintf("a = %d, b = %d\n", a, b); //30,30return 0;
}

二. 引用的性质和用途
2.1 引用的三大主要性质
1、引用在定义时必须初始化
定义引用时必须给出这个引用的被引用实体是谁,如:int &b; -- 是非法的。
演示代码2.1:
int main()
{int a = 10;int& b; //报错int& c = a; //初始化引用return 0;
}

2、一个变量可以有多个引用
我们可以为一个变量取多个别名。如演示代码2.2所示,给a变量取b、c、d三个别名是可行的。对a、b、c、d中的任意一个赋值,都会使a、b、c、d的值均发生改变。a、b、c、d共用一块内存空间。
演示代码2.2:
int main()
{int a = 10;int& b = a;int& c = a;int& d = a; //为a取b、c、d三个别名printf("a = %d, b = %d, c = %d, d = %d\n", a, b, c, d); //10,10,10,10c = 20;printf("a = %d, b = %d, c = %d, d = %d\n", a, b, c, d); //20,20,20,20return 0;
}

3、一个引用一旦引用了某个实体,就不能再引用其他实体
演示代码2.3中的b = c并不是将b变为变量c的引用,而是将变量c的值赋给b,通过打印b和c的地址,我们可以发现b和c并不共用一块内存空间,而赋值之后,a和b的值都变为了20。
演示代码2.3:
int main()
{int a = 10;int& b = a;int c = 20;b = c; //将c的值赋给b,而不是让b变为c的引用printf("&b = %p, &c = %p\n", &b, &c); //b和c的地址不一致printf("a = %d, b = %d\n", a, b); //a、b都变为了c的值20return 0;
}

正是因为引用一旦引用了某个实体之后就不能再引用其他实体,所以引用无法替代指针来实现链表数据结构。否则就无法实现链表的增、删等操作,链表的增删操作需要改变指针的指向。
2.2 引用的主要应用
1、引用做函数参数
要写一个swap函数,实现两个整形数据的交换,如果用C语言来写这个函数,就必须使用指针来作为函数的参数,即:void swap(int* px, int* py)。但是,如果使用C++来写,则可以用引用传参来替代指针传参,因为引用和被引用实体共用一块内存空间,引用传参使得函数内部可以控制实参所占用的内存空间,这是,swap可以声明为:void swap(int& rx, int& ry)。
演示代码2.4:
void swap(int& rx, int& ry)
{int tmp = rx;rx = ry;ry = tmp;
}int main()
{int x = 10, y = 20;printf("交换前:x = %d,y = %d\n", x, y); //10,20swap(x, y);printf("交换后:x = %d,y = %d\n", x, y); //20,10return 0;
}

至此,可以总结出函数的三种调用方法:
- 传值调用。
- 传地址调用。
- 传引用调用。
问题:void swap(int x, int y)和void swap(int& x, int& y)能否构成函数重载?
答案是可以的。因为其满足构成函数重载的条件之一 :参数的类型不同。
但是,在调用这两个swap函数时,会存在歧义。通过语句swap(x,y)调用,无法确定是调用swap(int x, int y)还是swap(int&x, int& y)。
2、引用做函数的返回值
在演示代码2.5中,定义函数int& Add(int x, int y),函数返回z的别名。我们希望这个函数能够对x+y进行计算。但是显然,这段代码是有潜在问题的,因为在add函数调用结束后,为add函数创建的栈帧会被销毁,这块栈空间会还给操作系统。此时再使用add函数的返回值,就会造成对内存空间的非法访问,而大部分情况下,编译器不会对非法访问内存报错。
演示代码2.5:
int& add(int x, int y)
{int z = x + y;return z;
}int main()
{int& ret = add(1, 2);printf("ret = %d\n", ret);return 0;
}
对于演示代码2.5的运行结果,可以分为两种情况讨论:
- 函数栈帧销毁后,编译器不对被销毁的栈空间进行清理,打印函数的返回值,结果依旧为x + y的值。
- 函数栈帧销毁后,编译器对被销毁的栈空间进行清理,函数的返回值为随机值。
在VS2019 编译环境下,演示代码2.5的运行结果为3,说明VS编译器不会清理被销毁的函数栈帧空间中内容。

既然VS编译器不会对被销毁的函数栈帧进行清理,那么是否在VS编译环境下,可以正常使用演示代码2.5中的add函数呢?答案显然是否定的,这可以从以下两个方面解释:
- 如果在其他编译环境下进行编译,则被销毁的函数空间可能会被清理,这样会降低代码的可移植性。
- 即使函数栈帧空间不被清理,但这块空间已经换给了操作系统,如果调用完add函数后再调用其他函数,那么原本为z开辟的空间可能会被覆盖,从而改变ret的值。
如演示代码2.6所示,第一次调用add函数使用ret来接收返回值,第二次调用add函数不接收返回值。但是第二次调用add函数之后,ret的值却变为了30,这是因为第二次调用add函数覆盖了第一次调用时创建的函数栈帧,原来第一次调用存放变量z的内存空间的内容由3变为了30,因此,程序运行的结果为30。这段代码在运行过程中栈帧的创建和销毁情况见图2.7。
演示代码2.6:
int& add(int x, int y)
{int z = x + y;return z;
}int main()
{int& ret = add(1, 2);cout << ret << endl;add(10, 20);cout << ret << endl;return 0;
}


总结(什么时候可以用引用返回,什么时候不可以):
- 如果出了函数作用域,函数返回的对象被销毁了,则不能使用引用类型作为返回值。
- 如果出了函数作用域,函数的返回对象还没有被销毁(存储返回对象的内存还没有还给操作系统),则可以使用引用作为返回值。
演示代码2.7给出了两种可以使用引用作为返回的情况,一种是以静态变量作为返回对象,另一种是返回对象为调用函数中开辟的一块内存空间中的内容(调用函数中开辟的数组)。
演示代码2.7:
int& func1()
{static int n = 0;++n;return n;
}char& func2(char* str, int i)
{return str[i];
}int main()
{cout << func1() << endl; //1cout << func1() << endl; //2char ch[] = "abcdef";for (int i = 0; i < strlen(ch); ++i){func2(ch, i) = '0' + i;}cout << ch << endl; //012345return 0;
}

思考问题:既然函数完成调用时才会返回,而调用完成时函数栈帧又会被销毁。那么,以值作为函数返回类型时,时如何从函数中接收返回值的呢?
就比如演示代码2.8中的add函数,函数返回值时add函数中的临时变量z的值,在主函数中的ret如何从add函数中接收z值。
演示代码2.8:
int add(int x, int y)
{int z = x + y;return z;
}int main()
{int ret = add(2, 3);return 0;
}
答案其实很简单,ret并不是直接从add函数栈帧的空间中接收返回值,而是在add函数完成调用、函数栈帧销毁之前,存储一个临时变量用于接收函数的返回值,然后在将临时变量的值赋给ret。
那么,这个临时变量存储在什么位置呢?分两种情况讨论:
- 如果返回值比较小,则使用寄存器充当临时变量。
- 如果返回值比较大,则将临时变量放在调用add函数的函数内部,在调用add函数之前在调用add的函数的栈帧中预先开辟一块空间用于存储临时变量。

三. 引用的效率测试
3.1 传值调用和传引用调用的效率对比
演示代码3.1分别执行100000次传值调用和100000次传引用调用,每次传值调用传给函数的形参的大小为40000bytes,记录传值调用和传引用调用消耗的时间。
程序运行结果显示,10000次传值调用耗时71ms,100000次传引用调用耗时2ms,传引用调用的效率远高于传值调用。这是因为传引用调用不用再为形参开辟一块内存空间,而为形参开辟空间存在一定的时间消耗。
演示代码3.1:
#include<iostream>
#include<time.h>
using namespace std;//大小为40000bytes的结构体
typedef struct A
{int arr[10000];
}A;void Testvaluefunc(A a) { }; //传值调用测试函数
void TestReffunc(A& a) { }; //传引用调用测试函数void TestRefAndValue1()
{A a;int i = 0;size_t begin1 = clock(); //记录开始传值调用的时间(传值调用100000次)for (i = 0; i < 100000; ++i){Testvaluefunc(a);}size_t end1 = clock(); //记录结束传值调用的时间size_t begin2 = clock(); //记录开始传引用调用的时间(调用100000次)for (i = 0; i < 100000; ++i){TestReffunc(a);}size_t end2 = clock();cout << "传值调用10000次耗费时间:" << end1 - begin1 << endl;cout << "传引用调用10000次耗费时间:" << end2 - begin2 << endl;
}

3.2 值返回和引用返回的效率对比
演示代码3.2分别执行100000次值返回函数和100000次引用返回函数,记录调用值返回函数和调用引用返回函数消耗的时间。程序运行结果表明,调用100000次值返回函数耗时136ms,调用100000次引用返回函数耗时2ms,引用返回的效率远高于值返回。
演示代码3.2:
#include<iostream>
#include<time.h>
using namespace std;typedef struct A
{int arr[10000];
}A;A a;A TestValuefunc2()
{return a;
}A& TestReffunc2()
{return a;
}void TestRefAndValue2()
{int i = 0;size_t begin1 = clock(); //记录开始时间(调用100000次)for (i = 0; i < 100000; ++i){TestValuefunc2();}size_t end1 = clock(); //记录结束时间size_t begin2 = clock(); //记录开始的时间(调用100000次)for (i = 0; i < 100000; ++i){TestReffunc2();}size_t end2 = clock(); //记录结束时间cout << "以值作为返回:" << end1 - begin1 << "ms" << endl;cout << "以引用作为返回:" << end2 - begin2 << "ms" << endl;
}int main()
{TestRefAndValue2(); //引用作为返回和值作为返回的效率测试return 0;
}

四. 常引用
4.1 权限放大和权限缩小问题
如果int& b = a,而a是整形常量,被const关键字修饰,那么b就不能作为a的别,因为a变量是只读的,而将b定义为int&类型,则表明b是可读可写的类型,b对a存在权限放大问题。
对于int a = 10,使用const int& b = a来表示a的别名是可以编译通过的。因为a为读写类型,而b为只读类型,b相对于a权限缩小,C++允许权限缩小。
总结:C++允许权限缩小,不允许权限放大。
演示代码4.1:
int main()
{//权限放大问题const int a = 10;//int& b = a; //报错const int& b = a; //编译通过//权限缩小int c = 10;const int& d = c; //能够编译通过return 0;
}
4.2 跨数据类型的引用问题
看一个很诡异的问题。在演示代码4.2中,定义一个双精度浮点型数据double d = 1.1,编译程序,出现下面的现象:
- 将d赋给int型数据i1,编译通过。
- 用int& i2 = d来作为d的引用(别名),编译报错。
- 但是,使用const int& i3 = d来作为d的引言,编译通过。
演示代码4.2:
int main()
{double d = 11.11;int i1 = d; //强转,编译通过//int& i2 = d; //编译报错const int& i3 = d; //编译通过printf("&d = %p\n", &d);printf("&i3 = %p\n", &i3);return 0;
}
那么,为什么const int& i3类型的可以作为d的引用,而int& i2却不行?问题出在强制类型转换上。要理解这个问题,首先要清楚强制类型转换的过程,强制类型转换(int i1 = d),并不是将d强转后的数据直接赋给i1,而是先将d强转为int类型数据的值存储在一个临时变量中,然后再将临时变量的值传给i1,详见图4.1。

临时变量具有常性,只可读不可改。因此,int& i2 = d就存在权限放大的问题,编译无法通过,而const int& i3 = d不会存在权限放大的问题,可以编译通过。但是,这里的i3就不再是d的别名,而是存储d强转为int类型数据值的临时变量的别名,因此i3和d的地址也就不同。演示代码4.2打印了i3和d的地址,表面他们不同,i3其实并不是d的别名。
提示:一定要弄清楚强转类型转换时临时变量做中间值的问题!

五. 引用和指针的区别
- 引用是定义一个变量的别名,而指针存储一个地址。
- 引用不占用额外的内存空间,而指针要占用4bytes或8bytes的内存空间。
- 引用在定义时必须初始化,而指针可以不初始化。(建议指针在定义时避免不初始化)。
- 引用一旦引用了某个实体,便不能更改被引用实体,而指针可以更改指向。
- 对引用自加,即对被引用的实体+1,指针自加,向后偏移一个指针类型的大小(bytes)。
- 没有多级引用,有多级指针。
- 访问实体时,引用直接由编译器处理即可,指针需要解应用。
- 没有空引用,但有空指针NULL。
- 引用相对于指针更加安全。
因为指针存在野指针、空指针等问题,造成指针过于灵活,所以指针的安全性不如引用。
引用的底层是通过指针来实现的。
引用最大的局限性在于不能更改引用实体,因此虽然引用的底层是通过指针实现的,但引用不能替代指针来实现链表数据结构。因为链表的操作需要更改指针的指向。
相关文章:
C++入门:引用
目录 一. 什么是引用 1.1 引用的概念 1.2 引用的定义 二. 引用的性质和用途 2.1 引用的三大主要性质 2.2 引用的主要应用 三. 引用的效率测试 3.1 传值调用和传引用调用的效率对比 3.2 值返回和引用返回的效率对比 四. 常引用 4.1 权限放大和权限缩小问题 4.2 跨…...
SpringSecurity的权限校验详解说明(附完整代码)
说明 SpringSecurity的权限校是基于SpringSecurity的安全认证的详解说明(附完整代码) (https://blog.csdn.net/qq_51076413/article/details/129102660)的讲解,如果不了解SpringSecurity是怎么认证,请先看下【SpringSecurity的安…...
Java-集合(5)
Map接口 JDK8 Map接口实现子类的特点 Map和Collection是并列关系,Map用于保存具有映射关系的数据:Key-ValueMap中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中Map中的key不允许重复,原因和HashSet一样Map…...
研制过程评审活动(四)设计定型阶段
1、设计定型阶段主要任务 设计定型的主要任务是对武器装备性能和使用要求进行全面考核,以确认产品是否达到《研制任务书》和《研制合同》的要求。 设计定型阶段应最终确定《产品规范》、《工艺规范》和《材料规范》的正式版本,并形成正式的全套生产图样、有关技术文件及目…...
【Linux】进程替换
文章目录进程程序替换替换原理替换函数函数返回值函数命名理解在makefile文件中一次生成两个可执行文件总结:程序替换时运行其它语言程序进程程序替换 程序要运行要先加载到内存当中 , 如何做到? 加载器加载进来,然后程序替换 为什么? ->冯诺依曼 因为CPU读取数据的时候只…...
LeetCode171-Excel表列序号(进制转换问题)
LeetCode171-Excel表列序号1、问题描述2、解题思路:进制转换3、代码实现1、问题描述 给你一个字符串columnTitle,表示Excel表格中得列名称。返回该列名称对应得列序号。 例如: A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 …...
React SSR
ReactDOMServer 参考链接:https://zh-hans.reactjs.org/docs/react-dom-server.html ReactDOMServer 对象允许你将组件渲染成静态标记。通常,它被使用在 Node 服务端上 // ES modules import * as ReactDOMServer from react-dom/server; // CommonJS v…...
如何系统地优化页面性能
页面优化,其实就是要让页面更快地显示和响应。由于一个页面在它不同的阶段,所侧重的关注点是不一样的,所以如果要讨论页面优化,就要分析一个页面生存周期的不同阶段。 通常一个页面有三个阶段:加载阶段、交互阶段和关…...
Vulnhub 渗透练习(八)—— THE ETHER: EVILSCIENCE
环境搭建 环境下载 靶机和攻击机网络适配都选 NAT 即可。 信息收集 主机扫描 两个端口,22 和 80,且 apache httpd 2.4.0~2.4.29 存在换行解析漏洞。 Apache HTTPD是一款HTTP服务器,它可以通过mod_php来运行PHP网页。其2.4.0~2.4.29版本中…...
华为OD机试题 - 水仙花数 2(JavaScript)| 代码+思路+重要知识点
最近更新的博客 华为OD机试题 - 字符串加密(JavaScript) 华为OD机试题 - 字母消消乐(JavaScript) 华为OD机试题 - 字母计数(JavaScript) 华为OD机试题 - 整数分解(JavaScript) 华为OD机试题 - 单词反转(JavaScript) 使用说明 参加华为od机试,一定要注意不要完全背…...
字符设备驱动基础(二)
目录 一、五种IO模型------读写外设数据的方式 二、阻塞与非阻塞 三、多路复用 3.1 应用层:三套接口select、poll、epoll 3.2 驱动层:实现poll函数 四、信号驱动 4.1 应用层:信号注册fcntl 4.2 驱动层:实现fasync函数 一、…...
看见统计——第三章 概率分布
看见统计——第三章 概率分布 参考 https://github.com/seeingtheory/Seeing-Theory中心极限定理 概率分布描述了随机变量取值的规律。 随机变量Random Variables 🔥 定义:将样本空间中的结果映射到实数的函数 XXX 称为随机变量(random variable)&a…...
【基于众包标注的语文教材句子难易度评估研究 论文精读】
基于众包标注的语文教材句子难易度评估研究 论文精读信息摘 要0 引言1 相关研究2 众包标注方法3 语料库构建3.1 数据收集3.1 基于五点量表的专家标注3.3 基于成对比较的众包标注4 特征及模型4.1 特征抽取4.2 模型与实验设计4.2.1 任务一:单句绝对难度评估4.2.2 任务二:句对相对…...
实例五:MATLAB APP design-APP登录界面的设计
一、APP 界面设计展示 注:在账号和密码提示框输入相应的账号和密码后,点击登录按钮,即可跳转到程序中设计的工作界面。 二、APP设计界面运行结果展示...
作用域和闭包:
1、LHS和RHS查询编译一段代码,需要js引擎和编译器(js引擎负责整个程序运行时所需的各种资源的调度,编译器只是js引擎的一部分,负责将JavaScript源码编译成机器能识别的机器指令,然后交给引擎运行)编译的过程…...
Vue常见面试题?
1、说说你对SPA单页面的理解,它的优缺点是什么? SPA(single-page application)仅在Web页面初始化时加载相应的HTML、JavaScript和CSS。一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机…...
前端借助Canvas实现压缩图片两种方法
一、具体代码 1、利用canvas压缩图片方法一 // 第一种压缩图片方法(图片base64,图片类型,压缩比例,回调函数)// 图片类型是指 image/png、image/jpeg、image/webp(仅Chrome支持)// 该方法对以上三种图片类型都适用 压缩结果的图片base64与原类型相同// …...
2023年美赛C题Wordle预测问题二建模及Python代码详细讲解
更新时间:2023-2-19 相关链接 (1)2023年美赛C题Wordle预测问题一建模及Python代码详细讲解 (2)2023年美赛C题Wordle预测问题二建模及Python代码详细讲解 (3)2023年美赛C题Wordle预测问题三、四…...
【算法】双指针
作者:指针不指南吗 专栏:算法篇 🐾或许会很慢,但是不可以停下来🐾 文章目录1.双指针分类2.双指针思想3.双指针应用1.双指针分类 常见问题分类 (1) 对于一个序列,用两个指针维护一段区间, 比如快速排序。 …...
Flutter-Widget-学习笔记
Widget 是整个视图描述的基础。 参考:https://docs.flutter.dev/resources/architectural-overview Widget 到底是什么呢? Widget 是 Flutter 功能的抽象描述,是视图的配置信息,同样也是数据的映射,是 Flutter 开发框…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
