C++ 中的 lambda 表达式

news2024/11/15 7:22:08

1.概念

lambda表达式实际上是一个匿名类的成员函数,该类由编译器为lambda创建,该函数被隐式地定义为内联。因此,调用lambda表达式相当于直接调用匿名类的operator()函数,这个函数可以被编译器内联优化(建议)。

编译器为每个 lambda 表达式创建一个唯一的类型,该类型具有一个重载的 operator() 函数,其参数和返回类型与 lambda 表达式的参数和返回类型相匹配。

例如快速排序算法,STL允许用户自定义比较方式,在C++11之前,通常使用仿函数实现。但是代码一旦很长,使用之处和仿函数实现的地方相隔甚远,而且如果仿函数的命名不规范,很容易造成使用上的困难。

仿函数,又叫做函数对象(functor,function object),因为实现仿函数的方式就是重载一个类的operator(),只是用起来跟函数一样,其本质依然是一个对象

2.语法

C++11的lambda表达式是一种允许内联函数的特性,它可以用于不需要重用和命名的代码片段。lambda表达式的一般形式是:

[capture clause] (parameters) mutable -> return-type { function body }
  • [captureclause]:捕捉列表。该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。
  • (parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略。
  • mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
  • ->return-type:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可以省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
  • {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

 以一个简单的例子理解lambda表达式的语法:

[]
{
    cout << "hello lambda" << endl;
}

 这一大坨就表示它是一个类型/对象(type、class),我们知道,在类型后加上(),就表示调用这个对象的构造函数,而lambda的语法有些不同,在它后面加上括号,就表示调用它。如下所示:

#include <iostream>
using namespace std;

int main()
{
    []
    {
        cout << "hello lambda" << endl;
    }();
    
    return 0;
}

输出:

hello lambda

l在这里是任意取的名字(实际上要根据含义),刚才提到,方括号和后面一坨东西,就相当于一个对象,一般情况下我们是不知道它的类型的,所以通常用auto接收。

 现在,最简形式的lambda表达式就写出来了,试着调用它:

#include <iostream>
using namespace std;


int main()
{
    auto l = []
    {
        cout << "hello lambda" << endl;
    };
    l();
    return 0;
}

输出: 

hello lambda

 注意:

  • 上面的例子和概念中的“内联”属性并没有关系。
  • lambda表达式在main函数之外定义也不影响结果。
  • lambda表达式的最后有分号。
  • lambda函数的参数列表和返回值类型不是必要的,但捕捉列表和函数体是不可省略的。习惯上不写返回值,让表达式自动推导。

3.基本语法的应用

现在我们对lambda表达式基本语法有了大致的了解,下面进行详细介绍。

示例1

int main()
{
	int id = 0;
	auto f = [id]() mutable//捕捉列表没有任何符号 "="、"&",表示以传值方式捕捉变量,
		//mutable是使得表达式内部可以修改捕捉到的变量,且捕捉后不再受外界变量id的影响
		{
			cout << "id:" << id << endl;
			++id;//没有mutable修饰,这里将编译错误
		};
	id = 42;
	f();//0
	f();//1
	f();//2

	cout << "id:" << id << endl;//42

	return 0;
}

输出:

id:0
id:1
id:2
id:42

这与设想的结果应该不同:既然变量id的值已经被更新为42,那么lambda表达式f打印出的值应该是42、43、44,这是为何呢?这个问题会在看完所有例子以后揭晓答案。

通过例1,最重要的是理解lambda的本质是一个仿函数,例1的lambda表达式等价于下面的代码:

image-20230301082521983

  • [id]中没有任何特殊符号,表示默认以传值方式捕捉变量,也就相当于拷贝一份变量id的副本到这个匿名函数中,且捕捉后不再受外界变量id的影响
  • mutable表示可以修改捕捉的变量,那么也就可以执行自增语句
  • 例1按照语句的执行顺序,在执行lambda表达式时,变量id的值为0时就已经被捕捉了,即使它被更新为42,后续调用lambda表达式时变量id仍然从0开始

但是,即使lambda表达式内部对变量id自增,最终变量id仍然为最后一次修改的值:42。

示例2

int main()
{
	int id = 0;
	auto f = [&id](int param)//参数param是值传递,每次传值都是一次临时拷贝
		{
			cout << "id:" << id << ", ";
			cout << "param:" << param << endl;
			++id;
			++param;
		};

	id = 42;
	f(7);// 42 7
	f(7);// 43 7
	f(7);// 44 7

	cout << "id:" << id << endl;// 45

	return 0;
}

例2和例1的区别:去掉了mutable,以传引用方式捕捉变量,新增参数param。

  • [&id],表示以引用方式捕捉变量id。那么匿名函数内部和外界处理的变量id就是同一个,函数内部和外部都会互相影响。因此在调用lambda表达式之前变量id被更新为42仍然会影响lambda表达式内部。
  • 参数param是值传递,每次传值都是一次临时拷贝

示例3

int main()
{
	int id = 0;
	auto f = [id]() mutable
		{
			cout << "id:" << id << endl;
			++id;

			static int x = 5;
			int y = 6;
			return id;
		};

	f();
	return 0;
}

这说明lambda表达式本质就是一个匿名函数(底层由仿函数实现) ,所有函数的内部都能定义不同类型的变量,也允许有返回值。

4.捕捉方式

基本方式

Lambda表达式的捕捉方式是指它如何访问外部变量,也就是定义在lambda表达式之外的变量。Lambda表达式的最基本的两种捕获方式是:按值捕获(Capture by Value)和按引用捕获(Capture by Reference)。

  • 按值捕获是指lambda表达式内部保存一份外部变量的副本,对这个副本进行操作不会影响原来的变量。

  • 按引用捕获是指lambda表达式内部直接使用外部变量的引用,对这个引用进行操作会影响原来的变量。

隐式和混合

除此之外,还有两种方式:隐式捕获混合方式。它们是两种更简便的捕获方式,它们可以让编译器自动推断需要捕获的外部变量。

隐式捕获:

  • [=]表示以值捕获的方式捕获所有外部变量(默认),成员函数包括this指针;
  • [&]表示以引用捕获的方式捕获所有外部变量,成员函数包括this指针。

混合方式是指在隐式捕获的基础上,显式地指定某些变量的不同捕获方式。

混合使用时,要求捕获列表中第一个元素必须是隐式捕获(&或=),然后后面可以跟上显式指定的变量名和符号。

混合使用时,若隐式捕获采用引用捕获&,则显式指定的变量必须采用值捕获的方式;若隐式捕获采用值捕获=,则显式指定的变量必须采用引用捕获的方式,即变量名前加&。

int main()
{
    int a = 123;
    int b = 456;
    auto f = [=, &b]() { // 隐式值捕获a,显式引用捕获b
        cout << a << endl; // 输出:123
        cout << b << endl; // 输出:456
        b = 789; // 修改b的值
    };
    f();
    cout << b << endl; // 输出:789
    
    return 0;
}

 输出:

123
456
789

补充

  • [=]以值捕获,是默认状态一般不写。

  • 不允许以相同方式重复捕捉,例如[=, a],前者已经表示以值捕获所有外部变量,后者就重复了。但是[=, &a]是被允许的,因为它们的捕获方式不同。

  • Lambda表达式的父作用域是指定义lambda表达式的那个作用域,通常是一个函数或者一个类。Lambda表达式的块作用域是指lambda表达式本身的作用域,它是一个匿名函数,可以在其他地方调用。

  • Lambda表达式可以捕获父作用域中的局部变量,但是不能捕获其他作用域或者非局部变量。Lambda表达式捕获父作用域中的局部变量时,要求这个变量必须是声明为final的,或者实际上是final的(即不会被修改)。Lambda表达式不能在自己的块作用域中声明和父作用域中同名的参数或者局部变量。

  • Lambda表达式之间不能相互赋值,因为它们的本质是函数对象。即使从文本层面看它们的名字相同,但是底层编译器给它们取的名字是不同的。

5.传递lambda表达式

C++传递lambda表达式的方法有以下几种:

  • 将lambda表达式转换为相应的函数指针(如果没有捕获任何变量)。使用std::function作为参数类型,它可以接受任何可调用对象(包括捕获变量的lambda表达式)。
  • 将lambda表达式赋值给一个变量,然后将这个变量传递给函数。
  • 使用decltype来推导出lambda表达式的类型,然后将这个类型作为模板参数传递给函数。

传递lambda表达式的第一种方法

将lambda表达式转换为相应的函数指针(如果没有捕获任何变量)。使用std::function作为参数类型,它可以接受任何可调用对象(包括捕获变量的lambda表达式)。

 对于第一种方法:要想将 lambda 表达式转换为函数指针,可以通过显式定义一个函数指针类型,然后用 lambda 表达式赋值给它。

但是,这需要满足两个条件:

1.lambda 表达式必须是静态的(即没有捕获任何变量)。

2.并且函数指针类型必须与 lambda 表达式的签名匹配。

考虑下面的示例:

#include <iostream>

int main() {
    auto lambda = []() { std::cout << "Lambda function" << std::endl; };

    // 将 lambda 表达式转换为函数指针
    void (*funcPtr)() = lambda;

    // 调用函数指针
    funcPtr();

    return 0;
}

 输出:

Lambda function

 三种方法的用例:

#include <iostream>
#include <functional>

void foo(std::function<bool(int)> f)
{
	std::cout << "Inside foo: " << f(5) << std::endl;
}

void bar(std::function<int(int, int)> f)
{
	std::cout << "Inside bar: " << f(10, 20) << std::endl;
}

void baz(std::function<int(int, int)> f)
{
	std::cout << "Inside baz: " << f(10, 20) << std::endl;
}

template<typename F>
void baz(F f)
{
	std::cout << "Inside baz: " << f(10, 20) << std::endl;
}
 
int main() {
	// 传递lambda表达式给foo函数,
	foo([](int x) { return x > 0; });

	// 将lambda表达式赋值给变量add,并传递给bar函数
	auto add = [](int a, int b) { return a + b; };
	bar(add);

	auto mul = [](int a, int b) { return a * b; };
	std::function<int(int, int)> sub = [](int p, int q) { return p - q; };
	//baz函数被重载,函数会根据类型调用更匹配的函数
	baz<decltype(mul)>(mul);// 传递lambda表达式和它的类型给变量baz
	baz(sub);//只传递表达式,类型由编译器自行推导

	return 0;
}

输出:

以set容器为例使用lambda表达式作为模板参数转递

下面以第三种方式为例:

(1).使用lambda 表达式

#include <iostream>
#include <set>

int main() {
    auto cmp = [](int a, int b) {
        return a > b;
    };

    std::set<int, decltype(cmp)> s(cmp); // 指定比较函数类型为 decltype(cmp)

    // 向 set 容器中插入元素
    s.insert(3);
    s.insert(1);
    s.insert(4);

    // 遍历输出 set 容器中的元素
    for (const auto& elem : s) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

 输出:

4 3 1

(2).不指定排序方式,使用默认的排序方式:

std::set<int> s;

 输出:

1 3 4

 (3).调用函数对象

#include <iostream>
#include <set>

// 自定义比较类
struct CustomCompare {
    bool operator()(int a, int b) const {
        return a > b;
    }
};

int main() {
    // 使用自定义比较类作为模板参数
    std::set<int, CustomCompare> s;

    // 向 set 容器中插入元素
    s.insert(3);
    s.insert(1);
    s.insert(4);

    // 遍历输出 set 容器中的元素
    for (const auto& elem : s) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出:

4 3 1

(4).调用函数指针 

bool compare(int a, int b) {
    return a > b;
}

 std::set<int, bool(*)(int, int)> s(&compare);

std::set 模板需要两个参数:

  1. 元素类型 (Key):指定集合中存储的元素类型。这是指定 std::set 类型的必需参数。

  2. 比较函数类型 (Compare):用于指定元素的排序方式。它可以是一个可调用对象,如函数指针、函数对象或 lambda 表达式。如果未提供该参数,则默认使用 std::less<Key>,即默认按照 < 运算符进行元素比较。

(1)这段代码中使用了decltype是为了推断出lambda表达式的类型。decltype是一个C++11引入的关键字,它可以根据表达式的类型返回一个类型。在这个例子中,decltype(cmp)就是lambda表达式的类型,它被用作set容器的第二个模板参数,指定了set中元素的比较方式。set的第三个模板参数需要一个比较函数类型,而lambda表达式本身没有一个固定的类型,decltype可以根据lambda表达式的operator()来推导出它的函数类型,从而满足set的要求。

如果不使用decltype,就需要显式地写出lambda表达式的类型,但这很麻烦,因为lambda表达式的类型是编译器生成的,并没有一个具体的名字。你就需要自己定义一个比较类或者函数,并将其作为模板参数传递给std::set。

在这里暂不讨论泛型lambda表达式。(C++14引入的新特性)

6.原理

class Add
{
public:
	Add(int base)
		:_base(base)
	{}
	int operator()(int num)
	{
		return _base + num;
	}
private:
	int _base;
};

int main()
{
	int base = 1;

	// 函数对象
	Add add1(base);
	add1(1);

	// lambda表达式
	auto add2 = [base](int num)
		{
			return base + num;
		};
	add2(1);

	return 0;
}

网站链接:https://godbolt.org/

通过汇编代码,可以看到编译器处理lambda表达式的方式和处理函数对象相同。原因是C++的lambda表达式底层实现是一个,它重载了operator()运算符,使得它可以像函数一样被调用。这个类还包含了lambda表达式捕获的变量,它们可以是值捕获或引用捕获。

一个lambda表达式产生一个临时对象,它可以用来初始化一个栈上的变量。这个对象有构造函数和析构函数,并且遵循所有C++规则。

这就是lambda表达式即使在上层看来名字相同也不能相互赋值的原因,编译器在底层给它们各自的函数对象的类起了不同的名字。例如在VS编译器中,具体类名为:lambda_uuid

类名的 uuid (Universally Unique Identifier)是一个用于标识类的唯一标识符。

lambda_uuid即lambda表达式的类型。所以lambda表达式的“匿名”属性是对于使用者而言的,对于编译器来说是有名的。

7.内联属性

C++的lambda表达式是一种方便的定义匿名函数对象(Go语言中的闭包)的方法。

它可以在调用或作为参数传递给函数的地方直接定义。通常lambda表达式用于封装一些传递给算法或异步函数的代码。

C++11中引入了λ表达式,它可以用来定义一个**内联 (inline)**的函数,作为一个本地的对象或者一个参数。内联函数是一种编译器优化技术,它可以避免函数调用的开销,提高执行效率。λ表达式可以被编译器自动内联展开,从而减少函数调用的次数。但是,并不是所有的λ表达式都会被内联,这取决于编译器的实现和优化策略。

一般来说,lambda表达式会被内联的条件是:

  • lambda表达式作为参数传递给一个内联函数
  • lambda表达式没有被保存或者传递到其他地方
  • lambda表达式没有从更外层的函数返回

如果不满足这些条件,可以使用noinline关键字来标记lambda参数,表示不要求内联。另外,编译器也会根据实现和优化策略来决定是否内联lambda表达式。

如果一个函数被调用的频率很低,甚至只有一次,那么内联属性使得它在被调用的位置展开,能减少调用函数创建栈帧的开销。lambda表达式的内联属性是默认的,只要编译器认为它可以在某处展开,那么它就像一个内嵌语句一样。

 8.应用场景分类

  1. STL 算法:Lambda 表达式经常与标准模板库(STL)中的算法一起使用,例如 std::for_each, std::transform, std::sort 等。这些算法接受函数对象作为参数,Lambda 表达式提供了一种轻量级的方式来定义这些函数对象,从而使算法更加灵活和通用。

  2. 容器操作:Lambda 表达式可以用于容器的各种操作,包括排序、查找、筛选、变换等。例如,使用 Lambda 表达式定义 std::setstd::map 的比较函数,或者在范围遍历中使用 Lambda 表达式进行元素的处理。

  3. 并发编程:在多线程编程中,Lambda 表达式可以用于创建线程函数或者传递任务给线程池。例如,在 std::thread 或者 std::async 的构造函数中使用 Lambda 表达式定义线程函数。

  4. 回调函数:Lambda 表达式常常用作回调函数,用于处理异步操作或者事件驱动的编程。例如,在 GUI 编程中,可以使用 Lambda 表达式作为按钮点击事件的处理函数。

  5. 函数对象的替代:Lambda 表达式可以替代简单的函数对象的定义,使代码更加简洁和易读。例如,在 std::function 或者 std::bind 中使用 Lambda 表达式定义函数对象。

  6. 延迟执行:Lambda 表达式可以用作延迟执行的一种方式,使得某些操作在需要时才被执行。例如,将 Lambda 表达式存储在 std::function 对象中,然后在需要时调用它。

后面我会在不用的应用场景下进行说明。

那么今天的分享就到此结束,下期再见~ 

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

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

相关文章

BGP第二篇(bgp邻居状态及影响邻居建立的因素)

1、bgp邻居状态 BGP对等体的交互过程中存在6种状态机&#xff1a; 空闲&#xff08;Idle&#xff09; 连接&#xff08;Connect&#xff09; 活跃 &#xff08;Active&#xff09; Open报文已发送&#xff08;OpenSent&#xff09; Open报文已确认&#xff08;OpenConfirm&…

Redis 源码安装和入门介绍

Linux下的redis源码安装 redis介绍 Redis 是一个开源&#xff08;BSD许可&#xff09;的&#xff0c;内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构&#xff0c;如 字符串&#xff08;strings&#xff09;&#xff0c;…

医疗图像处理2023年CVPR:Label-Free Liver Tumor Segmentation-无标签肝肿瘤分割

目录 一、摘要 二、介绍 三、相关工作 四、网络框架 1.位置选择 2.纹理处理 3.形状生成 4.后处理 5.参数设计 五、实验 1.数据集&#xff1a; 2.评价指标&#xff1a; 3.实现&#xff1a; 4.结果&#xff1a; 六、结论 一、摘要 通过在CT扫描中使用合成肿瘤&am…

秋招算法刷题10(栈和队列)

0509 232.用栈实现队列 class MyQueue {Deque<Integer> inStack;Deque<Integer> outStack;public MyQueue() {inStack new ArrayDeque<Integer>();outStack new ArrayDeque<Integer>();}public void push(int x) {inStack.push(x);}public int pop…

【计算机网络】计算机网络概述、计算机网络性能指标 习题1

0 1. 计算机网络可被理解为( )。 A.执行计算机数据处理的软件模块 B. 由自治的计算机互连起来的集合体 C.多个处理器通过共享内存实现的紧耦合系统 D. 用于共同完成一项任务的分布式系统 0 2.计算机网络最基本的功能是( )。 A.数据通信 B. 资源共享 C. 分布式处理 D. 信息综合…

关于一致性,你该知道的事儿(上)

关于一致性&#xff0c;你该知道的事儿&#xff08;上&#xff09; 前言一、缓存一致性二、内存模型一致性三、事务一致性四、分布式事务一致性4.1 分布式系统的一些挑战4.2 关于副本的一些概念4.3 分布式事务之共识问题4. 3.1 PC(two-phase commit, 2PC)4.3.2 Raft 三、后记参…

[240512] x-cmd 发布 v0.3.6: (se,wkp,ddgo...)x( kimi,gemini,gpt...)

目录 x-cmd 发布 v0.3.6新增了 jina 模块新增了 ddgo 模块新增了 se 模块wkp 模块新增了 writer 模块cosmo 模块 x-cmd 发布 v0.3.6 本次版本的最新引入的功能都是目的为了进一步探索 LLM 的使用。 本版本的改进分为两类&#xff1a;资讯类模块&#xff08;Wikipedia&#xf…

现代制造之Solidworks三维建模篇

现代制造 有现代技术支撑的制造业&#xff0c;即无论是制造还是服务行业&#xff0c;添了现代两个字不过是因为有了现代科学技术的支撑&#xff0c;如发达的通信方式&#xff0c;不断发展的互联网&#xff0c;信息化程度加强了&#xff0c;因此可以为这两个行业增加了不少优势…

【matlab基础知识代码】(十八)无约束最优化问题

min下面的x称为优化向量或者是决策变量 匿名函数法 >> f(x)(x(1)^2-2*x(1))*exp(-x(1)^2-x(2)^2-x(1)*x(2)); x0[0; 0]; [x,b,c,d]fminsearch(f,x0), x 0.6111 -0.3056 b -0.6414 c 1 d 包含以下字段的 struct: iterations: 72 funcCount: 137 algor…

【JavaEE 初阶(五)】文件操作和IO

❣博主主页: 33的博客❣ ▶️文章专栏分类:JavaEE◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多文件操作 目录 1.前言2.认识文件3.文件操作3.1File 属性3.2构造方法3.3File类方法 4.文件内容操作4.1R…

python内置类memoryview()详解

memoryview() Python 的一个内置class&#xff0c;可直接使用。它返回给定参数的“内存视图”对象。内存视图对象是一个对支持缓冲区协议&#xff08;如 bytes 或 bytearray&#xff09;的数据的“窗口”或“视图”&#xff0c;它允许你在不复制数据的情况下操作内存中的数据。…

【机器学习】 技术栈和开发环境搭建

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 博客目录 技术栈编程语言库框架编辑器项目IDE …

数据分析需要注意哪些法律法规

数据分析 前言一、数据处理过程二、数据收集阶段的法律规则数据收集应具备合法、正当、透明原则数据收集应坚持最小必要原则数据收集应遵守知情-同意规则数据收集应遵守目的明确性要求 三、数据储存的法律规则四、数据使用与处理的阶段的法律规则数据安全保护义务按照数据分级分…

Linux:文件IO

Linux&#xff1a;文件IO C语言 文件IOfopen Linux 文件IOopen接口close接口write接口read接口 内存文件管理struct filestruct files_struct文件描述符 fd 缓冲区 C语言 文件IO 在正式讲解Linux中是如何对文件进行IO前&#xff0c;我们先简单回顾以下C语言中&#xff0c;是如…

【牛客】SQL206 获取每个部门中当前员工薪水最高的相关信息

1、描述 有一个员工表dept_emp简况如下&#xff1a; 有一个薪水表salaries简况如下&#xff1a; 获取每个部门中当前员工薪水最高的相关信息&#xff0c;给出dept_no, emp_no以及其对应的salary&#xff0c;按照部门编号dept_no升序排列&#xff0c;以上例子输出如下: 2、题目…

项目1:STM32+DHT11+FreeRTOS+emwin+LCD

第一部分&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;************ 【屏幕显示DHT11数据】 面向对象的思想编写硬件驱动程序&#xff0c;DHT11采集环境中的温湿度数据。使用FreeRTOS提供的任务间通信、同步、互斥&#xff0c;将DHT…

【Linux】AlmaLinux 9.4版本发布

AlmaLinux 9.4 正式版发布&#xff0c;该版本基于 Redhat Enterprise 9.4&#xff0c;内核版本号&#xff1a; 5.14.0-427.13.1.el9_4.x86_64 相对于Rocky Linux&#xff0c; AlmaLinux更加的稳定&#xff0c;生产环境建议使用AlmaLinux来替代CentOS 7.x AlmaLinux 9.4版本系统…

MIPI DPHY HS传输模式SoT和EoT的传输值

目录 1. 高速传输模式的传输序列 2. SoT传输序列 3. EoT传输序列 1. 高速传输模式的传输序列 Mipi DPHY的高速数据传输&#xff08;HST&#xff1a;High Speed Transmission&#xff09;以突发&#xff08;Burst&#xff09;方式发生。 为了帮助接收机同步&#xff1a; (1) …

Python-VBA函数之旅-str函数

目录 一、str函数的常见应用场景 二、str函数使用注意事项 三、如何用好str函数&#xff1f; 1、str函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://myelsa1024.blog.csdn.net/ 一、str函数的常…

Redis-配置文件详解

Redis配置文件详解 units单位 配置大小单位&#xff0c;开头定义基本度量单位&#xff0c;只支持bytes&#xff0c;大小写不敏感。 INCLUDES Redis只有一个配置文件&#xff0c;如果多个人进行开发维护&#xff0c;那么就需要多个这样的配置文件&#xff0c;这时候多个配置 文…