@@ -430,6 +430,38 @@ bool find(const vector<int> &v, int target) {
430430}
431431```
432432
433+ 但有时,我们的函数可能写了额外的操作,做完查找后不想直接返回。用 `return` 提前返回的话,下面 `do_final` 部分就无法执行到,只能复读一遍。
434+
435+ ```cpp
436+ void find(const vector<int> &v, int target) {
437+ for (int i = 0; i < v.size(); ++i) {
438+ if (v[i] == target) {
439+ do_something();
440+ do_final();
441+ return;
442+ }
443+ }
444+ do_other();
445+ do_final();
446+ }
447+ ```
448+
449+ 改用 ` goto ` 来打断循环,又不美观了。
450+
451+ ``` cpp
452+ void find (const vector<int > &v, int target) {
453+ for (int i = 0; i < v.size(); ++i) {
454+ if (v[ i] == target) {
455+ do_something();
456+ goto final;
457+ }
458+ }
459+ do_other();
460+ final:
461+ do_final();
462+ }
463+ ```
464+
433465可以包裹一个立即调用的 Lambda 块 `[&] { ... } ()`,限制提前返回的范围:
434466
435467```cpp
@@ -448,47 +480,120 @@ void find(const vector<int> &v, int target) {
448480}
449481```
450482
483+ 这样,return 最多只能打断到当前 Lambda 函数结束的位置,而不能打断整个大函数了。
484+
451485## Lambda 复用代码
452486
487+ ``` cpp
488+ void calc_average () {
489+ int res = 0;
490+ int count = 0;
491+ for (int i = 0; i < cat_arr.size(); i++) {
492+ res += cat_arr[i].age;
493+ count += cat_arr[i].count;
494+ }
495+ for (int i = 0; i < dog_arr.size(); i++) {
496+ res += dog_arr[i].age;
497+ count += dog_arr[i].count;
498+ }
499+ for (int i = 0; i < pig_arr.size(); i++) {
500+ res += pig_arr[i].age;
501+ count += pig_arr[i].count;
502+ }
503+ }
504+ ```
505+
506+ 你是否被迫写出以上这种复读代码?大部分内容都是重复的,每次只有一小部分修改,导致不得不复读很多遍,非常恼人!
507+
508+ “设计模式”官腔的做法是额外定义一个函数,把重复的部分代码功能抽出来变成一个 ` cihou ` 模板函数,然后再 ` calc_average ` 里只需要调用三次这个 ` cihou ` 函数即可实现复用:
509+
510+ ``` cpp
511+ template <class T >
512+ void cihou (int &res, int &count, std::vector<T > const &arr) {
513+ for (int i = 0; i < arr.size(); i++) {
514+ res += arr[ i] .age;
515+ count += arr[ i] .count;
516+ }
517+ }
518+
519+ void calc_average() {
520+ int res = 0;
521+ int count = 0;
522+ cihou(res, count, cat_arr);
523+ cihou(res, count, dog_arr);
524+ cihou(res, count, pig_arr);
525+ }
526+ ```
527+
528+ 然而,额外定义一个函数也太大费周章了,而且还需要把所有用到的局部变量作为参数传进去!参数部分依然需要反复复读,并且还需要一个个指定所有参数的类型,写一长串模板等。最重要的是定义外部函数会污染了全局名字空间。
529+
530+ > {{ icon.fun }} 洁癖程序员:脏了我的眼!
531+
532+ 使用 Lambda,就可以让你在 `calc_average` 当前函数里“就地解决”,无需定义外部函数。
533+
534+ 更妙的是:Lambda 支持 `[&]` 语法,自动捕获所有用到的局部变量为引用!无需一个个传递局部变量引用作为函数参数,没有复读,更加无感。只有重复代码中真正区别的部分需要传参数。
535+
536+ ```cpp
537+ void calc_average() {
538+ int res = 0;
539+ int count = 0;
540+ auto cihou = [&] { // 局部 Lambda 的好处:自动帮你捕获 res 和 count!
541+ for (int i = 0; i < arr.size(); i++) {
542+ res += arr[i].age;
543+ count += arr[i].count;
544+ }
545+ };
546+ cihou(cat_arr);
547+ cihou(dog_arr);
548+ cihou(pig_arr);
549+ }
550+ ```
551+
552+ > {{ icon.tip }} 现在只有两个变量 ` res ` 和 ` count ` 可能还没什么,如果重复的部分用到一大堆变量,同时还有时候用到,有时候用不到的话,你就觉得 Lambda 好用了。
553+
554+ 例如字符串切片函数典型的一种实现中,因为“尾巴”的伺候和“主体”的伺候,就会产生重复代码:
555+
453556``` cpp
454557vector<string> spilt (string str) {
455558 vector<string > list;
456559 string last;
457560 for (char c: str) {
458561 if (c == ' ') {
459562 list.push_back(last);
460- last.clear() ;
563+ last = "" ;
461564 } else {
462- last.push_back(c) ;
565+ last += c ;
463566 }
464567 }
465568 list.push_back(last);
466569 return list;
467570}
468571```
469572
470- 上面的代码可以用 Lambda 复用:
573+ 上面的代码中重复的部分 `list.push_back(last);` 可以用 Lambda 复用,把重复的操作封装成局部的 Lambda :
471574
472575```cpp
473576vector<string> spilt(string str) {
474577 vector<string> list;
475578 string last;
476- auto push = [&] {
579+ auto push_last = [&] {
477580 list.push_back(last);
478- last.clear() ;
581+ last = "" ;
479582 };
480583 for (char c: str) {
481584 if (c == ' ') {
482- push ();
585+ push_last ();
483586 } else {
484- last.push_back(c) ;
587+ last += c ;
485588 }
486589 }
487- push ();
590+ push_last ();
488591 return list;
489592}
490593```
491594
595+ ## 打表法代替 if-else
596+
492597## 类内静态成员 inline
493598
494599在头文件中定义结构体的 static 成员时:
0 commit comments