【C++11】lambda匿名函数和包装器

目录

一,lambda匿名函数

1-1,lambda的引入

1-2,lambda表达式书写格式

1-3,lambda函数的名称

1-4,lambda捕获列表的使用

1-5,函数对象与lambda表达式

二,包装器

2-1,function包装器

2-2,bind包装器


一,lambda匿名函数

1-1,lambda的引入

        在C++中,lambda函数是一种简洁的匿名函数或表达式,能够轻松处理复杂的逻辑和数据操作。lambda匿名函数可替换复杂的函数指针或伪函数,可以解决复杂而繁琐的仿函数和函数指针的使用,以及让程序员能够将类似于函数的表达式用作接收函数指针或伪函数的函数的参数(这点与function的作用有关)。      

1-2,lambda表达式书写格式

        lambda匿名函数:[capture-list] (parameters) mutable -> return-type { statement }

        [capture-list]:捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量(捕获变量的值或引用‘&’)供lambda函数的函数体使用。

        (parameters):参数列表,与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略。

        mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。lambda常性限制的是捕捉列表中的参数,没有限制参数列表中的参数。

        ->returntype:lambda函数的返回值类型(注意:不是表达式返回类型,下面会详细解释这方面),没有返回值时此部分可省略。由于lambda返回值类型相当于使用decltype根据返回值推断得到,如果lambda不包含返回语句,推断出的返回类型将为void,因此返回类型除非必要,一般不需要写。若使用该指定返回类型,参数列表将不可省略(即使参数为空)。

        {statement}:lambda函数的函数体,与普通函数的函数体一样,包含实现功能的代码。

注意:在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为 空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。

#include <iostream>
#include <vector>  
#include <algorithm>
using namespace std;
struct Goods
{
    string _name;  // 名字
    double _price; // 价格
    int _evaluate; // 评价
    Goods(const char* str, double price, int evaluate)
        :_name(str)
        , _price(price)
        , _evaluate(evaluate)
    {}
};
struct ComparePriceLess //仿函数
{
    bool operator()(const Goods& gl, const Goods& gr)
    {
        return gl._price < gr._price; 
    }
};
struct ComparePriceGreater //仿函数
{
    bool operator()(const Goods& gl, const Goods& gr)
    {
        return gl._price > gr._price;
    }
};
int main()
{
    vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
   3 }, { "菠萝", 1.5, 4 } };
    //下面两个排序需要编写两个访函数
    sort(v.begin(), v.end(), ComparePriceLess()); //按价格从小到大排序
    sort(v.begin(), v.end(), ComparePriceGreater()); //按价格从大到小排序
    //下面两个排序使用lambda匿名函数,直接一个式子解决一种函数表达,可看出要比伪函数或函数指针(即直接函数实现)更简便
    sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._price < g2._price; });
    sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {return g1._price > g2._price; });
    /*上面[](const Goods& g1, const Goods& g2) {return g1._price < g2._price; }会自动推导函数提返回类型是bool,即与[](const Goods& g1, const Goods& g2)->bool {return g1._price < g2._price; }等效*/
    return 0;
}

1-3,lambda函数的名称

        上面的lambda使用是作为单独函数表达式,下面将lambda表达式用作名称来使用(将该匿名函数赋给一个变量,该变量就是此名称)。lambda函数表达式必须要使用auto类型来接收。lambda底层实际上是一个类的仿函数,它在C++中并不直接返回它的结果,而是创建了一个可调用的对象(一个函数对象)。因此,你不能直接将一个lambda表达式赋值给一个非函数对象类型的变量(如int)。编译器会报错,因为int类型期望一个int类型或与int型相似类型的值,但是得到了一个lambda表达式(一个类类型)。不仅如此,编译器只有在编译时才可以确定lambda生成的式子,不同编译器下生成的式子还可能还不同,因此只能用auto接收lambda表达式,这里使用typeid().name可看出。

测试一:lambda的调用原理

//调用错误,lambda函数的返回值是int,但本身返回值不是int,是一个类类型
int a = [](int x)->int {return 55 + 5l; };
//auto自动推演类型,调用正确
auto _a = [](int x)->int {return 55 + 5l; };
//赋予lambda函数表达式名称为_a,而lambda底层是类的访函数,按照仿函数的调用即可
int b = _a(5);

//上面lambda的调用相当于下面的类的仿函数调用

class A
{
public:
    int operator()(int x)
    {
        return 55 + 51;
    }
};

A _a;
int b = _a(5);

[](int x)->int {return 55 + 5l; };的调用相当于int x;A()(x);的调用

测试二:lambda原理调用的示例

#include <iostream>
using namespace std;

int main()
{
    int x = 10;
    //使用lambda函数捕获x的引用并修改它  
    auto m = [&x]() {x = x * x; }; //m是一个实现访函数的类
    m(); //lambda函数的调用 
    cout << "x: " << x << endl;  
    cout << typeid(m).name() << endl; 
    return 0;
}

        lambda表达式是一个匿名函数,也可理解为一个表达式,该函数无法直接调用,如果想要直接调用,通常需要借助auto将其赋值给一个变量,通过该名称变量调用。

1-4,lambda捕获列表的使用

        捕获列表说明:捕捉列表用于传入上下文中的数据(传值或引用),以便供lambda使用。这里捕获数据的方式有以下几种:

        [var]:表示值传递方式捕捉变量var

        [&var]:表示引用传递捕捉变量var

        [=]:表示值传递方式捕获当前作用域中所有的变量(包括this)

        [&]:表示引用传递捕获当前作用域中所有的变量(包括this)

        [this]:表示值传递方式捕捉当前的this指针

#include <iostream>
using namespace std;
int main()
{    
    int a = 10, b = 10;
    //值传递捕捉a,捕捉的是a的拷贝
    auto fun1 = [a, b]()mutable { a += 1; b += 1; return a + b; }; /*lambda默认是const函数,限制了捕捉列表的参数,这里要使用mutable取消对捕捉列表的限制*/
    cout << "fun1: a + b = " << fun1() << endl;
    cout << "a + b = " << a + b << endl;
    cout << endl;
    //引用传递捕捉b,捕捉的是b的引用
    auto fun2 = [&a, &b] {a += 1; b += 1; return a + b; }; /*捕捉列表引用捕捉,说明开发者想要对其修改,lambda没有对捕捉列表限制,可以修改*/
    cout << "fun2: a + b = " << fun2() << endl;
    cout << "a + b = " << a + b << endl;
    cout << endl;
    //值传递获取当前作用域所有变量,捕捉所有变量的拷贝
    int c = 10, d = 10;
    auto fun3 = [=]()mutable {c += 1; d += 1; return c + d; }; //与上面“值传递捕捉a”同理
    cout << "fun3: c + d = " << fun3() << endl;
    cout << "c + d = " << c + d << endl;
    cout << endl;
    //引用传递获取当前作用域所有变量,捕捉所有变量的引用
    auto fun4 = [&] {c += 1; d += 1; return c + d; }; //与上面“引用传递捕捉b”同理
    cout << "fun4: c + d = " << fun4() << endl;
    cout << "c + d = " << c + d << endl;
    cout << endl;
    //捕捉a的拷贝,其它数据的引用
    auto fun5 = [&, a]()mutable {a = 1; b = 1; c = 1; return a + b + c; };
    /*auto fun6 = [=, &a]()mutable {a = 1; b = 1; c = 1; return a + b + c; };这里也可捕捉a的引用,其它数据的拷贝*/
    cout << "fun5: a + b + c = " << fun5() << endl;
    cout << "a + b + c = " << a + b + c;
    cout << endl;
    return 0;
}

        这块需说明以下几个注意点:

        1,语法上捕捉列表可由多个捕捉项组成,并以逗号分割,上面最后一个例子运用的就是此原理。还有比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量。

        2,捕捉列表不允许变量重复传递,否则就会导致编译错误。比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复。

        4,在作用域中的lambda函数仅能捕捉当前作用域中局部变量,捕捉任何非此作用域或者
非局部变量都会导致编译报错。

        5,lambda表达式之间不能相互赋值,即使看起来类型相同,因为无论怎样lambda的类型都不可能一样,它的底层是类的仿函数,编译时确定的类型会有所不同。

        6,lambda底层实现了拷贝构造,但是禁掉了默认构造。

#include <iostream>
using namespace std;
void (*PF)(); //函数指针的声明
int main()
{
    auto a = []{cout << "Hello C++" << endl; };
    auto b = []{cout << "Hello C++" << endl; };

    /*a = b; 编译失败,lambda实现虽都一样,但两者的类型不一样,内部不存在不同类型间的赋值。从下面的输出可看出*/
    cout << typeid(a).name() << endl;
    cout << typeid(b).name() << endl;
    cout << endl;
    /*允许使用一个lambda表达式拷贝构造一个新的副本,两者的类型相同,但lambda对象不能默认实现构造*/

    //decltype(a) c; 默认构造的调用,编译失败
    auto c(a);
    cout << typeid(c).name() << endl;
    cout << typeid(a).name() << endl;
    cout << endl;
    c();
    //也可以将lambda表达式赋值给相同类型的函数指针
    PF = a;
    PF();
    return 0;
}

1-5,函数对象与lambda表达式

        C++的函数对象通常指的是仿函数。lambda与函数对象极为相似,实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator(),即仿函数。下面的lambda表达式与函数对象基本可理解为一体。

class Rate
{
public:
    Rate(double rate) : _rate(rate) {}
    double operator()(double money, int year)
    {
        return money * _rate * year;
    }
private:
    double _rate;
};
int main()
{
    //函数对象
    double rate = 0.49;
    Rate r1(rate);
    r1(10000, 2);
    //lamber表达式
    auto r2 = [=](double monty, int year)->double {return monty * rate * year; };
    r2(10000, 2);
    return 0;
}


二,包装器

2-1,function包装器

        function包装器也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。由于函数指针较为复杂,仿函数比较单一,只能实现一种功能,如上Goods的比较,lambda函数语法层中没有类型,auto接收的只是名称,它们各有特色,但比较零散。function包装器的主要作用是封装函数指针(包括普通函数)、函数对象(仿函数)、lambda函数(匿名函数),将它们同一类型,实现一个函数的调用。我们先观察下面代码。

代码一:

#include <iostream>
using namespace std;
template<class F, class T>
T useF(F f, T x)
{
    static int count = 0;
    cout << "count:" << ++count << endl;
    cout << "count:" << &count << endl;
    return f(x);
}
double f(double i)
{
    return i / 2;
}
struct Functor
{
    double operator()(double d) 
    {
        return d / 3;
    }
};
int main()
{
    //函数名(函数指针)
    cout << useF(f, 11.11) << endl;
    cout << endl;
    //函数对象(仿函数)
    cout << useF(Functor(), 11.11) << endl;
    cout << endl;
    //lamber表达式
    cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;
    cout << endl;
    return 0;
}

代码二:

#include <iostream>
using namespace std;
template<class F, class T>
T useF(F f, T x)
{
    static int count = 0;
    cout << "count:" << ++count << endl;
    cout << "count:" << &count << endl;
    return f(x);
}
int f1(double i) { return i / 2; }
double f2(double i) { return i / 3; }
double f3(double i) { return i / 4; }
double f4(int i) { return i / 5; }
int main()
{
    /*实例化出的函数返回类型、参数类型相同,输出的count相同,即同一个函数,但若是其中一个类型不同,将会实例化出不同的函数,即输出count不同*/
    cout << useF(f1, 11.11) << endl;
    cout << useF(f2, 11.11) << endl;
    cout << useF(f3, 11.11) << endl;
    cout << useF(f4, 11.11) << endl;
    return 0;
}

        通过上面的程序验证,我们会发现对于函数模板而言,当返回类型和参数类型一致的情况下,编译器不会重新实例化出一份新的函数,但对于函数指针、函数对象、lambda表达式而言,即便三者的函数返回类型、形参类型都相同,但useF函数模板还是实例化了三份。包装器function可以很好的解决上面的问题,将它们封装成一种函数。

std::function在头文件<functional>
类模板结构原型如下
        template <class T> function;    
        template <class Ret, class... Args>
        class function<Ret(Args...)>;
模板参数说明:
        Ret : 被调用函数的返回类型
        Args…:被调用函数的形参类型

使用方法如下:

#include <iostream>
#include<functional>
using namespace std;

template<class F, class T>
T useF(F f, T x)
{
    static int count = 0;
    cout << "count:" << ++count << endl;
    cout << "count:" << &count << endl;
    return f(x);
}

double f1(double i) { return i / 2; }
int f2(double i) { return i / 2; }
double f3(int i) { return i / 3; }

struct Functor
{
    double operator()(double d) { return d / 3; }
};

int main()
{
    //函数指针
    function<double(double)> fc1 = f1;
    fc1(11.11); //将f1封装成fc1,返回类型double、形参类型double
    cout << useF(fc1, 11.11) << endl;
    /*下面的函数指针形式输出发现与上面的不同,返回类型和参数类型只要有一个不同,函数模板实例化出的函数就不同*/
    function<double(int)> fcc1 = f2;  
    fcc1(11.11); //将f2封装成fc,此时返回类型int、形参类型double,与f2不同
    cout << useF(fcc1, 11.11) << endl;
    //封装函数返回类型和形参类型相同,调用函数相同
    function<double(double)> fcc2 = f3;
    fcc2(11.11); //将f3封装成fc2,此时返回类型double、形参类型double,与f3不同
    cout << useF(fcc2, 11.11) << endl;
    cout << endl;

    //函数对象
    function<double(double)> fc2 = Functor();
    fc2(11.11);
    cout << useF(fc2, 11.11) << endl;

    //lambda表达式
    function<double(double)> fc3 = [](double d)->double { return d / 4; };
    fc3(11.11);
    cout << useF(fc3, 11.11) << endl;

    return 0;
}

        function包装器封装时的函数返回类型与形参类型可以与原函数不同,当包装器包装后,此时的调用情况与上面代码二一样,即若函数返回类型和形参类型相同将不会再新实例化出一份函数。

        function包装器包装后的调用与原函数互不影响,如上fc1与fc两者调用的函数不同,这里可放心使用。

类的成员函数的包装

        类的成员函数分为静态成员函数和非静态成员函数。静态成员函数没有包含隐藏的this指针,函数名即为函数地址,包装时跟其它函数包装一样,没有任何变化。非静态成员函数由于第一个参数是隐藏的this指针,所以语法规定包装时第一个形参必须是对象的指针或对象,其次,类的成员函数名本身不是地址,所以这里传递时必须传递地址,即“&”。

#include <iostream>
#include<functional>
using namespace std;
class Plus
{
public:
    static int plusi(int a, int b)
    {
        return a + b;
    }
    double plusd(double a, double b)
    {
        return a + b;
    }
};

int f(int a, int b) { return a + b; }

int main()
{
    //普通函数
    function<int(int, int)> fc1 = f; 
    function<int(int, int)> f1 = &f;
    cout << fc1(1, 1) << "  " << f1(1, 1) << endl;
    cout << f << " " << &f << endl; //输出地址一样,加不加&都行

    //静态成员函数
    function<int(int, int)> fc2 = &Plus::plusi; 
    function<int(int, int)> fc = Plus::plusi;
    cout << fc2(1, 1) << "  " << fc(1, 1) << endl;
    cout << &Plus::plusi << " " << Plus::plusi << endl; //输出地址一样,加不加&都行

    //非静态成员函数
    //非静态成员函数需要对象的指针或者对象去进行调用,因为类的非静态成员函数第一个默认隐形的参数是this指针

    Plus plus;

    //对象指针。这里不能使用Plus::plusd,因为成员函数名不是地址
    function<double(Plus*, double, double)> fc3 = &Plus::plusd; 
    cout << fc3(&plus, 1, 1) << endl;  

    //对象。这里不能使用Plus::plusd

    function<double(Plus, double, double)> fc4 = &Plus::plusd;
    cout << fc4(plus, 1, 1) << "  " << fc4(Plus(), 1, 1) << endl;
    return 0;
}

2-2,bind包装器

        bind是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。它与function底层其实都是仿函数,返回的其实是一个可调用对象。

bind的作用有两个:

        1,调整可调用对象参数的顺序(通常意义不大,了解即可)。

        2,调整可调用对象参数的个数(具有一定的价值)。

bind原型结构如下

形式一:
        template <class Fn, class... Args>
        bind(Fn&& fn, Args&&... args);
形式二:(参数全部指定不能使用function接收,具体下面会说明)
        template <class Ret, class Fn, class... Args>
        bind(Fn&& fn, Args&&... args);

bind调用的一般形式:

1,auto万能接收

auto newCallable = bind(callable, arg_list); 

2,function接收

function<Ret(Args...)> newCallable = bind(callable, arg_list); 

         newCallable:是一个可调用对象,可以是函数、成员函数、函数对象或lambda表达式。

         arg_list:是一个传递给callable,并以逗号分隔的形参列表。若是直接给定 callable 的参数,当我们调用newCallable时,newCallable会调用callable,并传给指定的参数;若是 arg_list 中的参数存在占位符(placeholders占位符),则可以在稍后调用newCallable时提供这些参数。

        占位符placeholders表示参数的“占位”。占位符_1、_2等表示绑定对象被调用时应提供的参数。

#include <iostream>
#include<functional>
using namespace std;

int Sub(int a, int b)
{
    return a - b;
}

class Plus
{
public:
    static int plusi(int a, int b)
    {
        return a + b;
    }

    double plusd(double a, double b)
    {
        return a - b;
    }
};

int main()
{
    //普通函数的正常参数顺序使用
    int x = 10, y = 20;
    auto f1 = bind(Sub, 10, 20);
    cout << f1() << endl; //指定参数,不需要传递

    auto f2 = bind(Sub, placeholders::_1, placeholders::_2); //成员_1表示传递Sub第一个位置参数,_2表示传递第二个位置参数
    cout << f2(x, y) << endl; //占位符使用,x传递绑定对象f2的第一个参数,y传递第二个

    /*调整参数顺序,f2第一个参数接收Sub的第二个位置上的参数,第二个参数接受Sub的第一个位置上的参数(此运用了解一下,意义不大)*/
    function<int(int, int)> f3 = bind(Sub, placeholders::_2, placeholders::_1); 
    cout << f3(x, y) << endl;

    //类的非静态成员函数绑定
    Plus p;
    /*bind绑定Plus::plusd,此处要指名地址(成员函数名称不是地址),具体绑定到p对象上,后面是绑定参数*/
    function<double(double, double)> fc4 = bind(&Plus::plusd, p, placeholders::_1, placeholders::_2);
    cout << fc4(2, 3) << endl;

    function<double(double)> fc5 = bind(&Plus::plusd, Plus(), placeholders::_1, 20); //绑定匿名对象Plus上
    cout << fc5(2) << endl;

    //类的静态成员函数绑定
    auto fc6 = bind(Plus::plusi, 10, 20); //静态成员不属于任何类,无需指名具体对象
//function<int(int, int)>fc6 = bind(Plus::plusi, 5, 7);参数全部指定,此时不能使用function

    cout << fc6() << endl;
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

项目管理基础知识

项目管理基础知识 导航 文章目录 项目管理基础知识导航一、项目相关概念二、时间管理三、人员管理四、风险管理 一、项目相关概念 项目定义的三层意思 一定的资源约束:时间资源、经费资源、人力资源一定的目标一次性任务 里程碑 是项目中的重要时点或事件持续时间为零&…

PX4水下机器人源码分析

一、Px4版本1.14.1机型文件 PX4Autopilotmain\ROMFS\px4fmu_common\init.d\airframes路径下 这个脚本设置了BlueROV2&#xff08;重型配置&#xff09;的各种参数和初始化步骤&#xff0c;包括电池设置、通信设置、机架和旋翼配置以及PWM输出功能的映射。通过这些设置&#x…

unity制作app(10)--统一字体

1.载入字体&#xff0c;微软雅黑&#xff0c;需要3分钟左右 加载进来3个 2.font文件夹下创建一个txt&#xff0c;内部的内容如下&#xff1a; &#xfeff;啊阿埃挨哎唉哀皑癌蔼矮艾碍爱隘鞍氨安俺按暗岸胺案肮昂盎凹敖熬翱袄傲奥懊澳芭捌扒叭吧笆八疤巴拔跋靶把耙坝霸罢爸白柏…

AI视频教程下载:零基础学会DALL-E 、Midjourney、Microsoft Designer、Adobe Firefly

学完本课程会得到什么&#xff1a; 掌握ChatGPT、DALL-E 2、Midjourney、Microsoft Bing Chat、Microsoft Designer和Adobe Firefly&#xff0c;全面理解生成性AI及其应用 了解OpenAI及其在生成性AI领域的尖端研究 理解提示工程的重要性以及它如何帮助产生更好的输出和数据 …

【QGIS入门实战精品教程】5.3:CGCS2000转Lambert投影

参考阅读: 【GlobalMapper精品教程】081:WGS84/CGCS2000转Lambert投影 文章目录 一、加载实验数据二、投影转换三、批量投影转换一、加载实验数据 加载配套实验数据,如下图所示:图层为长沙市范围、长沙市酒店宾馆分布点位、湖南省酒店分布点位矢量数据。 双击图层,打开信…

【Vue】Vue2中的Vuex

目录 Vuex介绍Vuex 中的核心概念 在vue2中使用Vuex安装 Vuex创建一个 Vuex Store在 Vue 实例中使用 Vuex编写 Vuex 的 state、mutations 和 actions在组件中使用 Vuex Vuex的核心State组件中获取 Vuex 的状态mapState 辅助函数对象展开运算符 Getter基本使用示例 通过属性访问通…

Unity实现首行缩进两个字符

效果 在Unity中如果想实现首行缩进两个字符&#xff0c;你会发现按空格是没法实现的。 实现原理&#xff1a;用空白的透明的字替代原来的位置。 代码&#xff1a; <color#FFFFFF00>XXX</color> 赶紧去试试吧&#xff01;

《架演》共创者第一次线上沟通会议总结

《架演》共创者第一次线上沟通——启动会 会议主题&#xff1a;《架演》共创启动会议会议时间&#xff1a;2024年5月28日&#xff0c;20:00 - 21:00会议地点&#xff1a;腾讯会议主持人&#xff1a;寒山参会人员&#xff1a; 夏军、mirror、刘哥、悟缺席人员&#xff1a;可心、…

性能测试(一)—— 性能测试理论+jmeter的使用

1.性能测试介绍 定义&#xff1a;软件的性能是软件的一种非功能特性&#xff0c;它关注的不是软件是否能够完成特定的功能&#xff0c;而是在完成该功能时展示出来的及时性。 由定义可知性能关注的是软件的非功能特性&#xff0c;所以一般来说性能测试介入的时机是在功能测试完…

20240521在Ubuntu20.04下编译RK3588平台的IPC方案

20240521在Ubuntu20.04下编译RK3588平台的IPC方案 2024/5/21 15:27 viewproviewpro-ThinkBook-16-G5-IRH:~$ viewproviewpro-ThinkBook-16-G5-IRH:~$ md5sum RK3588_IPC_SDK.tar.gz 7481cc8d59f697a5fa4fd655de866707 RK3588_IPC_SDK.tar.gz viewproviewpro-ThinkBook-16-G5…

【vue-4】遍历数组或对象v-for

1、遍历数组 <ul><li v-for"(value,index) in web.number">index>{{index}}:value>{{value}}</li> </ul> 知识点&#xff1a; <ul>标签定义无序列表 举例&#xff1a; <ul><li>Coffee</li><li>Tea…

LeetCode199二叉树的右视图

题目描述 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 解析 这一题的关键其实就是找到怎么去得到当前是哪一层级&#xff0c;可以利用队列对二叉树进行层次遍历&#xff0c;但…

FFmpeg操作命令 - 精简版

PS&#xff1a;&#xff08;因为我只需要简单的操作&#xff0c;所以我整理出了这份笔记&#xff09; 原网址&#xff1a;30分钟带你入门&#xff0c;20个 FFmpeg操作命令&#xff0c;包你学会 - 知乎 大佬零声Github整理库整理的笔记非常的全面&#xff0c;想看完整版去上面…

Java | Leetcode Java题解之第102题二叉树的层序遍历

题目&#xff1a; 题解&#xff1a; class Solution {public List<List<Integer>> levelOrder(TreeNode root) {Queue<TreeNode> queue new LinkedList<>();List<List<Integer>> res new ArrayList<>();if (root ! null) queue.a…

前端开发框架Angular

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Angular概述 Angular是由Google开发并维护的一款开源前端开发框架。它最初被设计为用于构建单页面应用&#xff08;SPA&#xff09;&#xff0c;但随着版本的更新和发展&am…

torch.matmul()的用法

这篇文章记录torch.matmul()的用法 这里仿照官方文档中的例子说明&#xff0c;此处取整数随机数&#xff0c;用于直观的查看效果&#xff1a; vector x vector 两个一维向量的matmul相当于点积&#xff0c;得到一个标量 tensor1 torch.randint(1, 6, (3,)) tensor2 torch.…

LabVIEW通过以太网控制PLC程序开发

在使用LabVIEW通过以太网控制PLC程序开发时&#xff0c;需要综合考虑硬件、软件和通信协议的协调工作。以下是详细步骤、注意事项、重点和难点分析&#xff0c;以及几种实现方式及其特点的概述。 实现步骤 确定硬件和软件环境&#xff1a; 确定PLC型号和品牌&#xff08;如西门…

错误模块路径: ...\v4.0.30319\clr.dll,v4.0.30319 .NET 运行时中出现内部错误,进程终止,退出代码为 80131506。

全网唯一解决此BUG的文章&#xff01;&#xff01;&#xff01; 你是否碰到了以下几种问题&#xff1f;先说原因解决思路具体操作1、首先将你C:\Windows\Microsoft.NET\文件夹的所有者修改为你当前用户&#xff0c;我的是administrator。2、修改当前用户权限。3、重启电脑4、删…

你什么时候感觉学明白Java了?

学是学不明白Java的&#xff0c;要学明白Java&#xff0c;一定只能在工作以后。 1 在学习阶段&#xff0c;哪怕是借鉴别人的学习路线&#xff0c;其实依然会学很多不必要的技能&#xff0c;比如jsp&#xff0c;swing&#xff0c;或者多线程&#xff0c;或者设计模式。 2 或者…

业内宝刊!影响因子3连涨,OA可选,Elsevier旗下这本SSCI解救你的选刊纠结症

【SciencePub学术】今天小编给大家带来了一本经济类的高分优刊解读&#xff0c;隶属于Elsevier出版社&#xff0c;JCR1区&#xff0c;中科院2区&#xff0c;影响因子高达4.8&#xff0c;且实时影响因子还在持续上涨中&#xff0c;领域相符的学者可着重考虑&#xff01; Emergin…