Ai đó có thể giải thích? Tôi hiểu các khái niệm cơ bản đằng sau chúng nhưng tôi thường thấy chúng được sử dụng thay thế cho nhau và tôi bị lẫn lộn.
Và bây giờ chúng ta ở đây, chúng khác với chức năng thông thường như thế nào?
Ai đó có thể giải thích? Tôi hiểu các khái niệm cơ bản đằng sau chúng nhưng tôi thường thấy chúng được sử dụng thay thế cho nhau và tôi bị lẫn lộn.
Và bây giờ chúng ta ở đây, chúng khác với chức năng thông thường như thế nào?
Câu trả lời:
Một lambda chỉ là một chức năng ẩn danh - một chức năng được xác định không có tên. Trong một số ngôn ngữ, như Scheme, chúng tương đương với các hàm được đặt tên. Trong thực tế, định nghĩa hàm được viết lại dưới dạng ràng buộc lambda với một biến bên trong. Trong các ngôn ngữ khác, như Python, có một số khác biệt (khá bất cần) giữa chúng, nhưng chúng hành xử theo cùng một cách khác.
Một đóng cửa bất kỳ chức năng mà đóng trên các môi trường trong đó nó được xác định. Điều này có nghĩa là nó có thể truy cập các biến không có trong danh sách tham số của nó. Ví dụ:
def func(): return h
def anotherfunc(h):
return func()
Điều này sẽ gây ra lỗi, vì func
không đóng trên môi trường trong anotherfunc
- h
không xác định. func
chỉ đóng cửa trên môi trường toàn cầu. Điều này sẽ làm việc:
def anotherfunc(h):
def func(): return h
return func()
Bởi vì ở đây, func
được định nghĩa trong anotherfunc
và trong python 2.3 trở lên (hoặc một số như thế này) khi chúng gần như đóng đúng (đột biến vẫn không hoạt động), điều này có nghĩa là nó đóng trên anotherfunc
môi trường và có thể truy cập các biến bên trong nó Trong Python 3.1+, đột biến làm việc quá khi sử dụng các nonlocal
từ khóa .
Một điểm quan trọng khác - func
sẽ tiếp tục đóng cửa trên anotherfunc
môi trường ngay cả khi nó không còn được đánh giá anotherfunc
. Mã này cũng sẽ hoạt động:
def anotherfunc(h):
def func(): return h
return func
print anotherfunc(10)()
Điều này sẽ in 10.
Điều này, như bạn chú ý, không liên quan gì đến lambda - chúng là hai khái niệm khác nhau (mặc dù có liên quan).
Có rất nhiều nhầm lẫn xung quanh lambdas và đóng cửa, ngay cả trong các câu trả lời cho câu hỏi StackOverflow này ở đây. Thay vì hỏi các lập trình viên ngẫu nhiên, những người đã học về việc đóng cửa từ thực tiễn với các ngôn ngữ lập trình nhất định hoặc các lập trình viên không biết gì khác, hãy thực hiện một hành trình đến nguồn (nơi tất cả bắt đầu). Và vì lambdas và đóng cửa đến từ Lambda Compus được phát minh bởi Alonzo Church vào những năm 30 trước khi máy tính điện tử đầu tiên tồn tại, đây là nguồn mà tôi đang nói đến.
Lambda Tính là ngôn ngữ lập trình đơn giản nhất trên thế giới. Những điều duy nhất bạn có thể làm trong đó: ►
f x
. f
và x
là tham số duy nhất của nó)λ
(lambda), sau đó là tên tượng trưng (ví dụ x
), sau đó là một dấu chấm .
trước biểu thức. Điều này sau đó chuyển đổi biểu thức thành một hàm mong đợi một tham số . λx.x+2
lấy biểu thức x+2
và nói rằng biểu tượng x
trong biểu thức này là một biến bị ràng buộc - nó có thể được thay thế bằng một giá trị bạn cung cấp làm tham số. (λx.x+2) 7
. Sau đó, biểu thức (trong trường hợp này là một giá trị theo nghĩa đen) 7
được thay thế như x
trong phần phụ x+2
của lambda được áp dụng, do đó bạn nhận được 7+2
, sau đó giảm xuống 9
theo quy tắc arithologists thông thường.Vì vậy, chúng tôi đã giải quyết một trong những bí ẩn:
lambda là hàm ẩn danh từ ví dụ trên , λx.x+2
.
function(x) { return x+2; }
và bạn có thể ngay lập tức áp dụng nó cho một số tham số như thế này:
(function(x) { return x+2; })(7)
hoặc bạn có thể lưu trữ hàm ẩn danh này (lambda) vào một số biến:
var f = function(x) { return x+2; }
cái tên này có hiệu quả f
, cho phép bạn tham khảo và gọi nó nhiều lần sau đó, vd:
alert( f(7) + f(10) ); // should print 21 in the message box
Nhưng bạn đã không phải đặt tên cho nó. Bạn có thể gọi nó ngay lập tức:
alert( function(x) { return x+2; } (7) ); // should print 9 in the message box
Trong LISP, lambdas được làm như thế này:
(lambda (x) (+ x 2))
và bạn có thể gọi lambda như vậy bằng cách áp dụng nó ngay lập tức vào một tham số:
( (lambda (x) (+ x 2)) 7 )
Như tôi đã nói, những gì trừu tượng lambda làm là ràng buộc một biểu tượng trong biểu hiện phụ của nó, để nó trở thành một tham số thay thế . Một biểu tượng như vậy được gọi là ràng buộc . Nhưng nếu có các biểu tượng khác trong biểu thức thì sao? Ví dụ : λx.x/y+2
. Trong biểu thức này, biểu tượng x
bị ràng buộc bởi sự trừu tượng lambda λx.
trước nó. Nhưng biểu tượng khác, y
không bị ràng buộc - nó miễn phí . Chúng tôi không biết nó là gì và nó đến từ đâu, vì vậy chúng tôi không biết ý nghĩa của nó và giá trị của nó là gì , và do đó chúng tôi không thể đánh giá biểu thức đó cho đến khi chúng tôi hiểu được ý y
nghĩa của nó.
Trong thực tế, cùng đi với hai biểu tượng khác, 2
và +
. Chỉ là chúng ta đã quá quen thuộc với hai biểu tượng này đến nỗi chúng ta thường quên rằng máy tính không biết chúng và chúng ta cần nói cho chúng biết ý nghĩa của chúng bằng cách xác định chúng ở đâu đó, ví dụ như trong thư viện hoặc chính ngôn ngữ.
Bạn có thể nghĩ về các biểu tượng miễn phí như được định nghĩa ở một nơi khác, bên ngoài biểu thức, trong "bối cảnh xung quanh", được gọi là môi trường của nó . Môi trường có thể là một biểu hiện lớn hơn mà biểu thức này là một phần của (như Qui-Gon Jinn nói: "Luôn có một con cá lớn hơn";)), hoặc trong một thư viện, hoặc trong chính ngôn ngữ (như một ngôn ngữ nguyên thủy ).
Điều này cho phép chúng tôi chia biểu thức lambda thành hai loại:
Bạn có thể ĐÓNG một biểu thức lambda mở bằng cách cung cấp môi trường , định nghĩa tất cả các biểu tượng miễn phí này bằng cách ràng buộc chúng với một số giá trị (có thể là số, chuỗi, hàm ẩn danh hay còn gọi là lambdas, bất cứ điều gì).
Và ở đây có sự đóng cửa một phần:
Các đóng cửa của một biểu thức lambda là tập hợp cụ thể này các biểu tượng được định nghĩa trong bối cảnh bên ngoài (môi trường) mà cung cấp cho giá trị vào những biểu tượng miễn phí trong biểu thức này, làm cho chúng không tự do nữa. Nó biến một biểu thức lambda mở , vẫn chứa một số biểu tượng miễn phí "không xác định", thành biểu tượng đóng , không còn biểu tượng miễn phí nào nữa.
Ví dụ, nếu bạn có các biểu thức lambda sau: λx.x/y+2
, biểu tượng x
là ràng buộc, trong khi biểu tượng y
là miễn phí, do đó biểu thức là open
và không thể được đánh giá, trừ khi bạn nói gì y
nghĩa là (và cùng với +
và 2
, cũng là miễn phí). Nhưng giả sử rằng bạn cũng có một môi trường như thế này:
{ y: 3,
+: [built-in addition],
2: [built-in number],
q: 42,
w: 5 }
Đây môi trường cung cấp các định nghĩa cho tất cả các "undefined" (miễn phí) biểu tượng từ biểu thức lambda của chúng tôi ( y
, +
, 2
), và một số những biểu tượng thêm ( q
, w
). Các biểu tượng mà chúng ta cần được xác định là tập hợp con của môi trường này:
{ y: 3,
+: [built-in addition],
2: [built-in number] }
và đây chính xác là sự đóng cửa của biểu thức lambda của chúng tôi:>
Nói cách khác, nó đóng một biểu thức lambda mở. Đây là nơi đóng cửa tên đến từ nơi đầu tiên, và đây là lý do tại sao rất nhiều câu trả lời của mọi người trong chủ đề này không hoàn toàn chính xác: P
Chà, các thị trường doanh nghiệp của Sun / Oracle, Microsoft, Google, v.v ... đều đáng trách, bởi vì đó là cái mà họ gọi là các cấu trúc này trong ngôn ngữ của họ (Java, C #, Go, v.v.). Họ thường gọi "đóng cửa" những gì được cho là chỉ là lambdas. Hoặc họ gọi "đóng cửa" là một kỹ thuật cụ thể mà họ đã sử dụng để thực hiện phạm vi từ vựng, nghĩa là thực tế là một hàm có thể truy cập các biến được xác định trong phạm vi bên ngoài tại thời điểm định nghĩa của nó. Họ thường nói rằng hàm "bao quanh" các biến này, nghĩa là, bắt chúng vào một số cấu trúc dữ liệu để cứu chúng khỏi bị phá hủy sau khi hàm ngoài hoàn thành việc thực thi. Nhưng đây chỉ là một bài viết "tiếp cận văn hóa dân gian" và tiếp thị, mà chỉ khiến mọi thứ trở nên khó hiểu hơn,
Và nó thậm chí còn tồi tệ hơn vì thực tế là luôn có một chút sự thật trong những gì họ nói, điều đó không cho phép bạn dễ dàng bác bỏ nó là sai: P Hãy để tôi giải thích:
Nếu bạn muốn triển khai một ngôn ngữ sử dụng lambdas như công dân hạng nhất, bạn cần cho phép họ sử dụng các biểu tượng được xác định trong ngữ cảnh xung quanh (nghĩa là sử dụng các biến miễn phí trong lambdas của bạn). Và các ký hiệu này phải ở đó ngay cả khi hàm xung quanh trở lại. Vấn đề là các ký hiệu này bị ràng buộc với một số lưu trữ cục bộ của hàm (thường là trên ngăn xếp cuộc gọi), sẽ không còn ở đó nữa khi hàm trả về. Do đó, để lambda hoạt động theo cách bạn mong đợi, bạn cần bằng cách nào đó "nắm bắt" tất cả các biến miễn phí này từ bối cảnh bên ngoài của nó và lưu chúng cho sau này, ngay cả khi bối cảnh bên ngoài sẽ biến mất. Đó là, bạn cần phải tìm sự đóng cửacủa lambda của bạn (tất cả các biến bên ngoài mà nó sử dụng) và lưu trữ nó ở một nơi khác (bằng cách tạo một bản sao hoặc bằng cách chuẩn bị không gian cho chúng trả trước, ở một nơi khác ngoài ngăn xếp). Phương pháp thực tế bạn sử dụng để đạt được mục tiêu này là "chi tiết triển khai" ngôn ngữ của bạn. Điều quan trọng ở đây là việc đóng cửa , đó là tập hợp các biến miễn phí từ môi trường lambda của bạn cần được lưu ở đâu đó.
Mọi người đã không mất quá nhiều thời gian để bắt đầu gọi cấu trúc dữ liệu thực tế mà họ sử dụng trong các triển khai ngôn ngữ của họ để thực hiện việc đóng cửa như là "đóng cửa". Cấu trúc thường trông giống như thế này:
Closure {
[pointer to the lambda function's machine code],
[pointer to the lambda function's environment]
}
và các cấu trúc dữ liệu này đang được truyền xung quanh dưới dạng tham số cho các hàm khác, được trả về từ các hàm và được lưu trữ trong các biến, để biểu diễn lambdas và cho phép chúng truy cập vào môi trường kèm theo cũng như mã máy để chạy trong ngữ cảnh đó. Nhưng đó chỉ là một cách (một trong nhiều) để thực hiện đóng cửa, chứ không phải là đóng cửa.
Như tôi đã giải thích ở trên, việc đóng biểu thức lambda là tập hợp con của các định nghĩa trong môi trường của nó cung cấp các giá trị cho các biến miễn phí có trong biểu thức lambda đó, đóng biểu thức một cách hiệu quả (biến một biểu thức lambda mở , chưa thể đánh giá được một biểu thức lambda đóng , sau đó có thể được đánh giá, vì tất cả các biểu tượng có trong nó hiện được xác định).
Bất cứ điều gì khác chỉ là một "giáo phái vận chuyển hàng hóa" và "ma thuật voo-doo" của các lập trình viên và nhà cung cấp ngôn ngữ không biết về nguồn gốc thực sự của những khái niệm này.
Tôi hy vọng đó là câu trả lời của bạn. Nhưng nếu bạn có bất kỳ câu hỏi tiếp theo nào, vui lòng hỏi họ trong các nhận xét và tôi sẽ cố gắng giải thích rõ hơn.
Khi hầu hết mọi người nghĩ về các chức năng , họ nghĩ về các chức năng được đặt tên :
function foo() { return "This string is returned from the 'foo' function"; }
Chúng được gọi theo tên, tất nhiên:
foo(); //returns the string above
Với biểu thức lambda , bạn có thể có các hàm ẩn danh :
@foo = lambda() {return "This is returned from a function without a name";}
Với ví dụ trên, bạn có thể gọi lambda thông qua biến được gán cho:
foo();
Tuy nhiên, hữu ích hơn việc gán các hàm ẩn danh cho các biến, tuy nhiên, việc chuyển chúng đến hoặc từ các hàm bậc cao hơn, tức là các hàm chấp nhận / trả về các hàm khác. Trong rất nhiều trường hợp này, việc đặt tên hàm là không cần thiết:
function filter(list, predicate)
{ @filteredList = [];
for-each (@x in list) if (predicate(x)) filteredList.add(x);
return filteredList;
}
//filter for even numbers
filter([0,1,2,3,4,5,6], lambda(x) {return (x mod 2 == 0)});
Một bao đóng có thể là một hàm có tên hoặc ẩn danh, nhưng được biết đến như vậy khi nó "đóng" các biến trong phạm vi mà hàm được định nghĩa, nghĩa là bao đóng sẽ vẫn tham chiếu đến môi trường với bất kỳ biến ngoài nào được sử dụng trong tự đóng cửa. Đây là một đóng cửa có tên:
@x = 0;
function incrementX() { x = x + 1;}
incrementX(); // x now equals 1
Điều đó dường như không nhiều nhưng nếu điều này là tất cả trong một chức năng khác và bạn đã chuyển incrementX
sang một chức năng bên ngoài thì sao?
function foo()
{ @x = 0;
function incrementX()
{ x = x + 1;
return x;
}
return incrementX;
}
@y = foo(); // y = closure of incrementX over foo.x
y(); //returns 1 (y.x == 0 + 1)
y(); //returns 2 (y.x == 1 + 1)
Đây là cách bạn có được các đối tượng trạng thái trong lập trình chức năng. Vì không cần đặt tên "gia tăngX", bạn có thể sử dụng lambda trong trường hợp này:
function foo()
{ @x = 0;
return lambda()
{ x = x + 1;
return x;
};
}
Không phải tất cả các bao đóng là lambdas và không phải tất cả các lambdas là đóng cửa. Cả hai đều là chức năng, nhưng không nhất thiết theo cách chúng ta quen biết.
Lambda về cơ bản là một hàm được định nghĩa nội tuyến hơn là phương thức khai báo hàm chuẩn. Lambdas có thể thường xuyên được truyền xung quanh như các đối tượng.
Đóng cửa là một chức năng bao quanh trạng thái xung quanh của nó bằng cách tham chiếu các trường bên ngoài cơ thể của nó. Các trạng thái kèm theo vẫn còn trên các yêu cầu đóng cửa.
Trong một ngôn ngữ hướng đối tượng, các bao đóng thường được cung cấp thông qua các đối tượng. Tuy nhiên, một số ngôn ngữ OO (ví dụ C #) triển khai chức năng đặc biệt gần với định nghĩa về các bao đóng được cung cấp bởi các ngôn ngữ chức năng thuần túy (chẳng hạn như lisp) không có đối tượng để bao quanh trạng thái.
Điều thú vị là việc giới thiệu Lambdas và Closures trong C # mang chương trình chức năng đến gần hơn với cách sử dụng chính.
Nó đơn giản như thế này: lambda là một cấu trúc ngôn ngữ, tức là cú pháp đơn giản cho các hàm ẩn danh; đóng cửa là một kỹ thuật để thực hiện nó - hoặc bất kỳ chức năng hạng nhất nào, đối với vấn đề đó, được đặt tên hoặc ẩn danh.
Chính xác hơn, bao đóng là cách một hàm hạng nhất được biểu diễn trong thời gian chạy, như một cặp "mã" của nó và một môi trường "đóng" trên tất cả các biến không cục bộ được sử dụng trong mã đó. Bằng cách này, các biến đó vẫn có thể truy cập được ngay cả khi phạm vi bên ngoài nơi chúng bắt nguồn đã được thoát.
Thật không may, có nhiều ngôn ngữ ngoài kia không hỗ trợ các hàm như các giá trị hạng nhất hoặc chỉ hỗ trợ chúng ở dạng bị tê liệt. Vì vậy, mọi người thường sử dụng thuật ngữ "đóng cửa" để phân biệt "hàng thật".
Từ quan điểm của ngôn ngữ lập trình, chúng hoàn toàn là hai thứ khác nhau.
Về cơ bản đối với một ngôn ngữ hoàn chỉnh Turing, chúng ta chỉ cần các yếu tố rất hạn chế, ví dụ trừu tượng hóa, ứng dụng và rút gọn. Tính trừu tượng và ứng dụng cung cấp cách bạn có thể xây dựng biểu thức lamdba và rút gọn làm giảm ý nghĩa của biểu thức lambda.
Lambda cung cấp một cách bạn có thể trừu tượng hóa quá trình tính toán. ví dụ, để tính tổng của hai số, một quá trình lấy hai tham số x, y và trả về x + y có thể được trừu tượng hóa. Trong lược đồ, bạn có thể viết nó dưới dạng
(lambda (x y) (+ x y))
Bạn có thể đổi tên các tham số, nhưng tác vụ hoàn thành không thay đổi. Trong hầu hết tất cả các ngôn ngữ lập trình, bạn có thể đặt tên cho biểu thức lambda là các hàm được đặt tên. Nhưng không có nhiều khác biệt, chúng có thể được coi là khái niệm chỉ là cú pháp đường.
OK, bây giờ hãy tưởng tượng làm thế nào điều này có thể được thực hiện. Bất cứ khi nào chúng ta áp dụng biểu thức lambda cho một số biểu thức, vd
((lambda (x y) (+ x y)) 2 3)
Chúng ta chỉ có thể thay thế các tham số bằng biểu thức được ước tính. Mô hình này đã rất mạnh mẽ. Nhưng mô hình này không cho phép chúng tôi thay đổi giá trị của các biểu tượng, ví dụ: Chúng tôi không thể bắt chước thay đổi trạng thái. Do đó chúng ta cần một mô hình phức tạp hơn. Để rút gọn, bất cứ khi nào chúng ta muốn tính toán ý nghĩa của biểu thức lambda, chúng ta đặt cặp ký hiệu và giá trị tương ứng vào một môi trường (hoặc bảng). Sau đó, phần còn lại (+ xy) được đánh giá bằng cách tra cứu các ký hiệu tương ứng trong bảng. Bây giờ nếu chúng tôi cung cấp một số nguyên thủy để hoạt động trực tiếp trên môi trường, chúng tôi có thể mô hình hóa các thay đổi của trạng thái!
Với nền tảng này, hãy kiểm tra chức năng này:
(lambda (x y) (+ x y z))
Chúng tôi biết rằng khi chúng tôi đánh giá biểu thức lambda, xy sẽ bị ràng buộc trong một bảng mới. Nhưng làm thế nào và ở đâu chúng ta có thể nhìn lên z? Trên thực tế z được gọi là một biến miễn phí. Phải có một môi trường bên ngoài có chứa z. Mặt khác, ý nghĩa của biểu thức không thể được xác định chỉ bằng ràng buộc x và y. Để làm rõ điều này, bạn có thể viết một cái gì đó như sau trong sơ đồ:
((lambda (z) (lambda (x y) (+ x y z))) 1)
Vì vậy, z sẽ được liên kết với 1 trong một bảng bên ngoài. Chúng ta vẫn nhận được một hàm chấp nhận hai tham số nhưng ý nghĩa thực sự của nó cũng phụ thuộc vào môi trường bên ngoài. Nói cách khác, môi trường bên ngoài đóng trên các biến miễn phí. Với sự trợ giúp của tập hợp!, Chúng ta có thể làm cho hàm trở nên trạng thái, nghĩa là nó không phải là một hàm theo nghĩa toán học. Những gì nó trả về không chỉ phụ thuộc vào đầu vào, mà cả z.
Đây là một cái gì đó bạn đã biết rất rõ, một phương pháp của các đối tượng hầu như luôn dựa vào trạng thái của các đối tượng. Đó là lý do tại sao một số người nói "đóng cửa là đối tượng của người nghèo." Nhưng chúng ta cũng có thể coi các đối tượng là sự đóng cửa của người nghèo vì chúng ta thực sự thích các chức năng hạng nhất.
Tôi sử dụng lược đồ để minh họa các ý tưởng do sơ đồ đó là một trong những ngôn ngữ sớm nhất có sự đóng cửa thực sự. Tất cả các tài liệu ở đây được trình bày tốt hơn nhiều trong SICP chương 3.
Tóm lại, lambda và đóng cửa là những khái niệm thực sự khác nhau. Một lambda là một chức năng. Một bao đóng là một cặp lambda và môi trường tương ứng để đóng lambda.
Khái niệm giống như được mô tả ở trên, nhưng nếu bạn đến từ nền tảng PHP, điều này sẽ giải thích thêm bằng cách sử dụng mã PHP.
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, function ($v) { return $v > 2; });
hàm ($ v) {trả lại $ v> 2; } là định nghĩa hàm lambda. Chúng tôi thậm chí có thể lưu trữ nó trong một biến, vì vậy nó có thể được tái sử dụng:
$max = function ($v) { return $v > 2; };
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max);
Bây giờ, nếu bạn muốn thay đổi số lượng tối đa được phép trong mảng được lọc thì sao? Bạn sẽ phải viết một hàm lambda khác hoặc tạo một bao đóng (PHP 5.3):
$max_comp = function ($max) {
return function ($v) use ($max) { return $v > $max; };
};
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max_comp(2));
Một bao đóng là một hàm được đánh giá trong môi trường của chính nó, có một hoặc nhiều biến ràng buộc có thể được truy cập khi hàm được gọi. Họ đến từ thế giới lập trình chức năng, nơi có một số khái niệm đang chơi. Các bao đóng giống như các hàm lambda, nhưng thông minh hơn theo nghĩa là chúng có khả năng tương tác với các biến từ môi trường bên ngoài nơi xác định bao đóng.
Đây là một ví dụ đơn giản hơn về việc đóng PHP:
$string = "Hello World!";
$closure = function() use ($string) { echo $string; };
$closure();
Câu hỏi này đã cũ và có nhiều câu trả lời.
Bây giờ với Java 8 và Lambda chính thức là các dự án đóng cửa không chính thức, nó làm sống lại câu hỏi.
Câu trả lời trong ngữ cảnh Java (thông qua Lambdas và bao đóng - có gì khác biệt? ):
"Một bao đóng là một biểu thức lambda được ghép nối với một môi trường liên kết từng biến tự do của nó với một giá trị. Trong Java, các biểu thức lambda sẽ được thực hiện bằng các phương thức đóng, vì vậy hai thuật ngữ đã được sử dụng thay thế cho nhau trong cộng đồng."
Nói một cách đơn giản, đóng cửa là một mẹo về phạm vi, lambda là một chức năng ẩn danh. Chúng ta có thể nhận ra việc đóng với lambda thanh lịch hơn và lambda thường được sử dụng như một tham số được truyền cho hàm cao hơn
Một biểu thức Lambda chỉ là một hàm ẩn danh. trong java đơn giản, ví dụ, bạn có thể viết nó như thế này:
Function<Person, Job> mapPersonToJob = new Function<Person, Job>() {
public Job apply(Person person) {
Job job = new Job(person.getPersonId(), person.getJobDescription());
return job;
}
};
trong đó lớp Hàm chỉ được xây dựng trong mã java. Bây giờ bạn có thể gọi mapPersonToJob.apply(person)
một nơi nào đó để sử dụng nó. đó chỉ là một ví dụ Đó là một lambda trước khi có cú pháp cho nó. Lambdas một cắt ngắn cho điều này.
Khép kín:
Lambda trở thành một bao đóng khi nó có thể truy cập các biến ngoài phạm vi này. Tôi đoán bạn có thể nói phép thuật của nó, nó kỳ diệu có thể bao quanh môi trường mà nó được tạo ra và sử dụng các biến bên ngoài phạm vi của nó (phạm vi bên ngoài. Vì vậy, rõ ràng, việc đóng cửa có nghĩa là lambda có thể truy cập OUTER SCOPE.
trong Kotlin, lambda luôn có thể truy cập vào bao đóng của nó (các biến nằm trong phạm vi bên ngoài của nó)
Nó phụ thuộc vào việc một hàm có sử dụng biến ngoài hay không để thực hiện thao tác.
Biến ngoài - biến được định nghĩa bên ngoài phạm vi của hàm.
Biểu thức Lambda không trạng thái vì nó phụ thuộc vào tham số, biến nội bộ hoặc hằng số để thực hiện các thao tác.
Function<Integer,Integer> lambda = t -> {
int n = 2
return t * n
}
Đóng trạng thái giữ vì nó sử dụng các biến bên ngoài (tức là biến được xác định bên ngoài phạm vi của thân hàm) cùng với các tham số và hằng số để thực hiện các hoạt động.
int n = 2
Function<Integer,Integer> closure = t -> {
return t * n
}
Khi Java tạo bao đóng, nó giữ biến n với hàm để nó có thể được tham chiếu khi được truyền cho các hàm khác hoặc được sử dụng ở bất cứ đâu.