【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.pswp.cn/bicheng/15491.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/15491.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/15491.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

信息系統管理工程師知識點

信息系統管理工程師知識點 損壞包括自然災害、物理損壞&#xff08;磁盤壞、設備使用壽命&#xff0c;外力破損&#xff09;、設備故障&#xff08;停電、電磁干擾&#xff09;。 泄漏包括電磁輻射&#xff08;偵聽微機損傷過程&#xff09;、乘機而入&#xff08;合法用戶進…

一天了解一個機器學習模型——機器學習基礎知識

人工智能的兩大任務——預測和決策 預測包括對輸入目標的模式識別、標簽分類、回歸、預測未來數據、聚類 決策需要機器產生行動&#xff0c;改變狀態&#xff0c;如下圍棋、自動駕駛 支持人工智能的四大類技術 搜索——結合算法探索分支的好壞&#xff0c;從而做出決策&…

如何使用maven運行SpringBoot程序?

目錄 一、什么是maven 二、什么是SpringBoot 三、如何使用maven運行SpringBoot程序&#xff1f; 一、什么是maven Maven&#xff1a;簡化Java項目構建的自動化工具 在軟件開發的世界里&#xff0c;Maven以其強大的項目管理和構建自動化功能&#xff0c;為Java開發者提供了…

內存泄漏及其解決方法

1. 系統崩潰前的現象 垃圾回收時間延長&#xff1a;從原本的約10ms增長至50ms&#xff0c;Full GC時間也由0.5s增加至4-5s。Full GC頻率增加&#xff1a;最短間隔可縮短至1分鐘內發生一次。年老代內存持續增長&#xff1a;即使經過Full GC&#xff0c;年老代內存未見明顯釋放。…

容器化:ES和Kibana

1 緣起 最近在學習使用ES&#xff0c; 為了找一個功能強大的可視化工具&#xff0c;之前使用了ES-Head&#xff0c;可以滿足學習需求。 閑暇時間又折騰了另一個工具Kibana&#xff0c; 分享如下。 Kibana優點&#xff1a; 用戶友好性&#xff1a;Kibana提供直觀易用的用戶界面…

Strategy設計模式

Strategy設計模式舉例。 看圖&#xff1a; 代碼實現&#xff1a; #include <iostream>using namespace std;class FlyBehavior { public:virtual void fly() 0; };class QuackBehavior { public:virtual void quack() 0; };class FlyWithWings :public FlyBehavior …

數據庫(vb.net+OleDB+Access)簡易學生信息管理系統

在我們日常生活當中&#xff0c;數據庫一詞往往離不開我們的編程界&#xff0c;在學校、倉庫等方面起著存儲數據及數據關系作用的文件。相較于Excel&#xff0c;Access可以存儲無限多的記錄&#xff0c;內容也十分豐富&#xff0c;例如文本、數字、日期、T&F等。而且不需要…

k8s命令式對象管理和配置

kubectl補全: # dnf install -y bash-completion # echo "source <(kubectl completion bash)" >> ~/.bashrc # kubectl completion bash > /etc/bash_completion.d/kubectl 命令式對象管理 kubectl命令 # 查看所有pod kubectl get pod # 查看某個po…

gbk轉utf-8

你們曾經有沒有因為文件的編碼問題而苦惱過&#xff1f;在Windows下開發時&#xff0c;尤其是項目初期&#xff0c;如果沒有特別注意文件的字符編碼問題&#xff0c;等到項目變大后&#xff0c;用Git對比代碼時&#xff0c;很可能會發現一些亂碼。這時才意識到字符編碼的重要性…

LLM——探索大語言模型在心理學方面的應用研究

1. 概述 心理學經歷了多次理論變革&#xff0c;目前人工智能&#xff08;AI&#xff09;和機器學習&#xff0c;特別是大型語言模型&#xff08;LLMs&#xff09;的使用&#xff0c;預示著新研究方向的開啟。本文詳細探討了像ChatGPT這樣的LLMs如何轉變心理學研究。它討論了LL…

docker- 鏡像 導出導入

文章目錄 前言docker- 鏡像 導出導入1. 導出2. 刪除鏡像3. 導入鏡像 前言 如果您覺得有用的話&#xff0c;記得給博主點個贊&#xff0c;評論&#xff0c;收藏一鍵三連啊&#xff0c;寫作不易啊^ _ ^。 ??而且聽說點贊的人每天的運氣都不會太差&#xff0c;實在白嫖的話&…

Nginx 從入門到精通-Nginx-Web服務器的瑞士軍刀

在當今互聯網高速發展的時代&#xff0c;作為Web服務器的Nginx可謂是一把"瑞士軍刀"&#xff0c;其強大的功能和出色的性能備受青睞。然而&#xff0c;僅僅停留在"會用"的層面是遠遠不夠的&#xff0c;要充分發揮Nginx的潛力&#xff0c;我們還需要深入了解…

SpringBoot Validation自定義注解之校驗指定最小整數

1&#xff0c;引入核心關鍵依賴 <!--數據校驗--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency> 2&#xff0c;自定義注解 package com.taia.ym…

忘記“也是一門學問:機器如何忘記自己學到的知識?

在信息時代&#xff0c;我們常常希望人工智能能夠學到更多的知識&#xff0c;變得更加智能。但你是否想過&#xff0c;有時候讓機器"忘記"一些它學到的東西&#xff0c;也是一件很重要的事&#xff1f; 隨著用戶隱私保護意識的提高和相關法律法規的出臺&#xff0c;…

深入理解內聯函數(C語言)

目錄 1.什么是內聯函數2.內聯函數與宏3.編譯器對內聯函數的處理4.參考文獻 1.什么是內聯函數 很多人都會知道&#xff0c;可以將比較小的函數寫成內聯函數的形式&#xff0c;這樣會節省函數調用的開銷&#xff0c;具體是什么樣的開銷呢&#xff1f; 一個函數在執行過程中&…

v-if 與 v-show(vue3條件渲染)

v-if 是“真正”的條件渲染&#xff0c;因為它會確保在切換過程中條件塊內的事件監聽器和子組件適當地被銷毀和重建。 v-if 也是惰性的&#xff1a;如果在初始渲染時條件為假&#xff0c;則什么也不做——直到條件第一次變為真時&#xff0c;才會開始渲染條件塊。 相比之下&a…

Java—單例模式

什么是單例模式&#xff1f; 單例模式是一種軟件設計模式&#xff0c;它確保一個類只有一個實例&#xff0c;并提供一個全局訪問點來訪問該實例。在單例模式中&#xff0c;類自身負責創建自己的唯一實例&#xff0c;并且保證在整個應用程序中只能訪問到這個實例。 實現步驟&a…

IDEA通過tomcat運行注意事項

配置run--》edit configurations 以下的A B部分要保持一致 A和B的路徑要保持一致

前端vue項目遇到的問題01——那些初級問題

前端vue項目遇到的問題01——那些初級問題 1. npm install 問題1.1 依賴沖突1.1.1 詳細問題1.1.2 報錯原因1.1.3 解決問題1.1.3.1 方式1——無視沖突1.1.3.1 方式2——更換依賴版本 1.2 nodejs版本問題1.3 node版本正確的情況&#xff08;audit問題&#xff09;&#xff08;這個…

Java鏈表簡介

在Java中使用鏈表作為一種數據結構&#xff0c;并將其與MySQL作為底層數據庫進行集成&#xff0c;涉及幾個關鍵方面&#xff0c;包括數據存儲、數據操作的效率、以及如何在應用層和數據庫層之間映射數據結構。下面是對這些方面的分析&#xff1a; ### Java中的鏈表數據結構 鏈…