4. Lambda funksiyalaridan foydalanishga misollar
C++da lambda ifodalar. Lambda ifodalari C#, C++ kabi imperativ tillarga yaqinda qoʻshila boshlagan funksional tillarning xususiyatlaridan (xususiyati, xarakteristikasi) biri hisoblanadi. Lambda ifodalari har qanday ifoda ichida yaratilishi mumkin bo'lgan nomsiz lokal funksiya deb ataladi. Shunday qilib, tushunish kerak bo'lgan birinchi narsa - C++ tilidagi lambda ifodalar anonim funksiyalarni yozishning qisqa shakli hisoblanadi. Masalan:
//1-kod
#include
#include
#include
#include
using namespace std;
int main() {
vector srcVec;
for (int val = 0; val < 10; val++) {
srcVec.push_back(val);
}
for_each(srcVec.begin(), srcVec.end(), [](int _n) {
cout << _n << " ";
});
cout << endl;
return EXIT_SUCCESS;
}
Aslida, bu kod aynan quyidagicha bo’lishi kerak:
//2-kod
#include
#include
#include
#include
using namespace std;
class MyLambda {
public: void operator ()(int _x) const { cout << _x << " "; }
};
int main() {
vector srcVec;
for (int val = 0; val < 10; val++) {
srcVec.push_back(val);
}
for_each(srcVec.begin(), srcVec.end(), MyLambda());
cout << endl;
return EXIT_SUCCESS;
}
Ushbu kodning komplyatsiyasi quyidagi natijani beradi:
0 1 2 3 4 5 6 7 8 9
Birinchidan, 1-koddan lambda ifodasi har doim [] bilan boshlanishini (qavslar bo'sh bo'lmasligi mumkin), keyin esa ixtiyoriy parametrlar ro'yxati, so'ngra funksiya tanasining o'zi kelishini ko'rish mumkin. Ikkinchidan, qaytish qiymatining turi ko'rsatilmadi va sukut bo'yicha lambda voidni qaytaradi. Uchinchidan, 2-kodda sukut bo'yicha konstanta metodi hosil bo'ladi.
//3-kod
#include
#include
#include
#include
using namespace std;
int main() {
vector srcVec;
for (int val = 0; val < 10; val++) {
srcVec.push_back(val);
}
int result = count_if(srcVec.begin(), srcVec.end(), [] (int _n) {
return (_n % 2) == 0;
});
cout << result << endl;
return EXIT_SUCCESS;
}
Bunda lambda unar predikat rolini o'ynaydi, ya'ni qaytish turi bool bo'ladi, garchi biz buni hech qayerda ko'rsatmagan bo'lsak ham. Lambda ifodasida bitta qaytish mavjud bo'lganda, kompilyator qaytariladigan qiymatning turini o'zi chiqaradi. Agar quyidagi koddagi kabi lambda ifodasida if yoki switch (yoki boshqa murakkab tuzilmalar) mavjud boʻlsa, kompilyatorga endi ishonib boʻlmaydi:
//4-kod
#include
#include
#include
#include
#include
using namespace std;
int main() {
vector srcVec;
for (int val = 0; val < 10; val++) {
srcVec.push_back(val);
}
vector destVec;
transform (srcVec.begin(), srcVec.end(),
back_inserter(destVec), [] (int _n) {
if (_n < 5)
return _n + 1.0;
else if (_n % 2 == 0)
return _n / 2.0;
else
return _n * _n;
});
ostream_iterator outIt(cout, " ");
copy(destVec.begin(), destVec.end(), outIt);
cout << endl;
return EXIT_SUCCESS;
}
4-kod kompilyatsiya qilinmaydi, masalan, Visual Studio har bir qaytish uchun xato yozadi:
«error C3499: a lambda that has been specified to have a void return type cannot return a value»
Kompilyator qaytariladigan qiymatning o'zi turini aniqlay olmaydi, shuning uchun biz uni aniq ko'rsatishimiz kerak:
//5-kod
#include
#include
#include
#include
#include
using namespace std;
int main() {
vector srcVec;
for (int val = 0; val < 10; val++) {
srcVec.push_back(val);
}
vector destVec;
transform(srcVec.begin(), srcVec.end(),
back_inserter(destVec), [] (int _n) -> double {
if (_n < 5)
return _n + 1.0;
else if (_n % 2 == 0)
return _n / 2.0;
else
return _n * _n;
});
ostream_iterator outIt(cout, " ");
copy(destVec.begin(), destVec.end(), outIt);
cout << endl;
return EXIT_SUCCESS;
}
Endi kompilyatsiya muvaffaqiyatli bo'ladi va natija kutilganidek:
1 2 3 4 5 25 3 49 4 81
5-kodga qo'shgan yagona narsa - bu -> double ko’rinishida lambda ifodasi qaytarish turi ko’rsatilgan. Sintaksis biroz g'alati va C++ dan ko'ra ko'proq Haskellga o'xshaydi. Ammo "chapda" (funksiyalarda bo'lgani kabi) qaytarish turini ko'rsatish ishlamaydi, chunki kompilyator uni ajrata olishi uchun lambda [] dan boshlanishi kerak.
Do'stlaringiz bilan baham: |