Lambdas là một trong những bổ sung hoàn toàn mới cho C ++ 11 và đã thay đổi cách chúng ta viết code trong C ++. Bất kỳ code C ++ hiện đại nào đều không hoàn chỉnh nếu không sử dụng lambdas cho phép tạo các hàm ẩn danh tại chỗ và biến C ++ thành một Ngôn ngữ lập trình hàm (Functional Programming) chính thức đầy đủ.

Vì cú pháp cũng như cách sử dụng còn tương đối mới nên nhiều lập trình viên C ++ vẫn gặp chút khó khăn khi viết và sử dụng các kịch bản.

Bài viết này sẽ mô tả cú pháp, cách sử dụng và khả năng ứng dụng của lambdas và cách nó giúp viết code C ++ ngắn, có thể bảo trì, có chức năng và hiện đại.

Nhưng trước khi hiểu lambdas là gì và sử dụng nó, chúng ta cần hiểu một chút về Lập trình hàm.

Lập trình hàm là gì?

Nói ngắn gọn, lập trình hàm là viết các hàm chương trình tương tự như hàm toán học. Ví dụ, hãy xem xét hàm toán học sau:

Hàm này trả về bình phương của x và là một hàm độc lập, không phụ thuộc, cũng không tác động đến bất kỳ điều gì bên ngoài phạm vi hàm. Cho một đầu vào x, đầu ra sẽ luôn luôn là x * x.

Chúng ta cũng hãy xem xét các hàm toán học đa thức như (x + y)2 (toàn bộ bình phương) được viết dưới dạng

Chức năng này có thể đơn giản được chia thành nhiều chức năng nhỏ hơn như

Tại đây, đầu ra của hàm chỉ phụ thuộc vào các tham số đầu vào. Với một đầu vào nhất định, hàm sẽ luôn tạo ra cùng một đầu ra.

Các đặc điểm khác của hàm là các tham số được truyền vào đối số là Bất biến. Trong cả hai hàm trên f(x)2 và f (x, y)2, các tham số x và y là bất biến. Chúng được sử dụng để tính toán, nhưng không được thay đổi vì các hàm toán học luôn tạo ra các giá trị mới từ các giá trị hiện có. Đó là lý do trong toán học, chúng ta không thấy hàm nào như:

Nhưng các hàm làm x ++ lại phổ biến trong C ++ và các ngôn ngữ lập trình khác. Lập trình hàm muốn chúng ta viết code giống như các hàm toán học trong đó các hàm:

  1. Không phụ thuộc vào, cũng không thay đổi bất cứ điều gì bên ngoài hàm.
  2. Mọi thứ là Bất biến, nếu chúng ta thay đổi thứ gì đó, nó sẽ tạo ra một cái mới chứ không phải thay đổi các mục hiện có

Tại sao sử dụng Lập trình chức năng?

Trong thế giới của (các) CPU đa lõi, nơi chương trình chạy song song, một chương trình hàm có thể thực thi nhiều CPU(s) một cách an toàn mà không lo bị khóa quá mức vì nó không sử dụng hoặc sửa đổi bất kỳ tài nguyên chung nào.

Lập trình hàm không phải là mới, chỉ là với sự xuất hiện của (các) CPU đa lõi, tiềm năng thực sự đã bộc lộ.

Cú pháp của Lambda

Cú pháp của lambda bao gồm [], () và {}. Đoạn code dưới đây là cú pháp lambda hợp lệ và sẽ được trình biên dịch biên dịch thành công

Trong đoạn code này:

- [] là Capture List

- () là nhà cung cấp đối số hàm (Function Argument)

- {} là triển khai lambda (Implementation)

Chúng ta có thể tạo một lambda rất đơn giản như in hello world như sau:

Tuy nhiên, lambda không thể tự động gọi chính nó, chúng ta cần phải gọi chúng một cách rõ ràng. Chúng ta có thể gọi lambda tại chỗ theo cách tương tự như cách chúng ta gọi bất kỳ hàm bình thường nào khác như:

Lambdas với tư cách là một hàm cũng có thể trả về giá trị và kiểu trả về của lambda được mô tả bằng cách sử dụng cú pháp -> như:

Ta có thể thu thập giá trị trả về của lambda trong bất kỳ biến nào dưới dạng:

Cũng giống như bất kỳ hàm thông thường nào khác, ta cũng có thể truyền các tham số trong hàm lambda bên trong `()` như

Các hàm lambda không cần phải được gọi tại chỗ, ta có thể giữ lambda bên trong Con trỏ hàm và gọi nó ở một nơi mà chúng ta chọn.

Ta có thể sử dụng từ khóa auto trong C ++ hoặc sử dụng mẫu std::function <> để giữ các hàm, chúng ta cũng có thể sử dụng con trỏ hàm kiểu C int(* lambdaFn)(int) cho điều tương tự, nhưng thường bị tránh vì cú pháp phức tạp. Ví dụ: hãy sử dụng std::function<> để lấy Tham chiếu hàm

Hàm lambda cũng giống như hàm toán học trong đó nó sẽ luôn trả về 101 khi giá trị 100 được chuyển cho nó.

Ta cũng có thể sử dụng auto thay thế khi lấy tham chiếu hàm:

Tạo Lambda cho f(x)2 và f(x,y)2

Đối với hàm f(x) = x * x, chúng ta có thể viết các hàm lambda dưới dạng

 

và đối với hàm f(x, y) 2 = x2 + y2 + 2xy, chúng ta có thể viết lambda là:

Như bạn có thể thấy với các lambdas này rằng nó phục vụ cả mục đích của lập trình hàm, tức là nó không phụ thuộc vào, cũng không thay đổi bất kỳ thứ gì bên ngoài hàm cũng như coi các biến đầu vào là bất biến.

Những lợi ích khác của code phiếm hàm này là gì?

Ta sẽ không tạo nhiều hàm trong phạm vi toàn cục để tồn tại vĩnh viễn. Tất cả các hàm lambda bên trong đều không có sẵn ở bên ngoài và sẽ nằm ngoài phạm vi ngay sau khi hàm được thực thi.

Đồng thời, các lambdas này đảm bảo rằng ta không tác động đến các biến trong phạm vi bởi vì ngay cả khi các lambdas được tạo tại chỗ bên trong một hàm, nó sẽ không thể truy cập bất kỳ biến cục bộ nào được khai báo trong phạm vi. Ví dụ, trong đoạn code dưới đây, không thể truy cập biến localvar bên trong hàm lambda

Capture List[] của lambda

Capture List [] được sử dụng để cung cấp các biến phạm vi cục bộ cho các hàm lambda mà không cần chuyển chúng một cách rõ ràng vào bên trong danh sách đối số tham số.

Các biến phạm vi cục bộ có thể được cung cấp bằng giá trị (tức là bản sao) hoặc bằng tham chiếu. Để chuyển một giá trị, chúng ta cần chỉ định các biến phạm vi cục bộ trong Capture List. Chỉ các biến được đề cập trong Capture List mới được cung cấp cho hàm lambda như được mô tả bên dưới:

Để truy cập tất cả các phần tử, ta có thể chỉ định tất cả chúng trong Capture List như:

hoặc ta có thể sử dụng = trong Capture List, vì tất cả các biến phạm vi cục bộ đều có

Các tham số truyền qua giá trị là bất biến, ta không thể thay đổi giá trị của chúng:

Điều này được thực hiện trong lambda để kích hoạt tính bất biến của lập trình hàm, nhưng chúng ta vẫn có thể sử dụng cơ chế & tham chiếu C ++ để chuyển biến phạm vi cục bộ bằng cách tham chiếu và thay đổi các giá trị. Những thay đổi này sẽ được phản ánh trên toàn cục.

Tạo Lambda cho f (x, y) 2 bằng cách sử dụng Capture List

Chúng ta có thể sử dụng cơ chế Capture List để triển khai hàm lambda mà không cần chuyển bất kỳ tham số nào như:

Sử dụng Capture List bên trong lớp

Danh sách chụp cũng có thể được sử dụng bên trong lớp, tuy nhiên, trong một hàm lớp, chỉ this mới khả dụng, vì vậy chúng ta chỉ có thể chuyển this trong Capture List để truy cập các biến lớp bên trong lambdas:

 

 

Đó là tất cả về Lambdas. Hy vọng nó có thể giúp mọi người hiểu rõ và sử dụng tốt hơn trong code của mình.

Tổng hợp việc làm IT - Software trên VietnamWorks
VietnamWorks InTECH
Theo Medium