2016-04-29 14 views
6

Như tôi hiểu, trong các ngôn ngữ như Haskell, và cũng như một phần của phép tính lambda, mỗi biểu thức lambda có phạm vi riêng của nó, vì vậy nếu tôi có các biểu thức lambda lồng nhau như: \x -> (\x -> x) thì tham số \x đầu tiên khác với tham số thứ hai \x. Trong Java nếu bạn làm điều này bạn nhận được một lỗi biên dịch, giống như nếu bạn sử dụng x một lần nữa làm tên thông số hoặc tên biến cục bộ trong lambda nếu nó đã được sử dụng bên trong phạm vi kèm theo, ví dụ: dưới dạng tham số phương thức.Tại sao các biểu thức lambda java không đưa ra một mức độ phạm vi mới?

Không ai biết tại sao Java thực hiện các biểu thức lambda theo cách này - tại sao không để chúng giới thiệu cấp độ phạm vi mới và hoạt động giống như một lớp ẩn danh? Tôi cho rằng đó là do một số hạn chế hoặc tối ưu hóa, hoặc có thể vì lambdas đã bị hack vào ngôn ngữ hiện tại?

+0

Làm thế nào để bạn tham khảo các x ngoài trong lambda lồng nhau bằng các ngôn ngữ như vậy? –

+1

@SotiriosDelimanolis Bạn không nhất thiết phải có khả năng, đây là một quyết định thiết kế. Bạn có thể e. g. cũng không truy cập vào biến cục bộ x từ một lớp ẩn danh, nơi bạn định nghĩa một x khác hoàn toàn hợp lệ. – Vampire

+2

Có thể trùng lặp của [Biến đã được xác định trong phương thức lambda] (https://stackoverflow.com/questions/22773003/variable-is-already-defined-in-method-lambda) – ZhekaKozlov

Trả lời

10

Đây là hành vi tương tự như đối với các khối mã khác trong Java.

này đưa ra một lỗi biên dịch

int a; 
{ 
    int a; 
} 

trong khi điều này không

{ 
    int a; 
} 
{ 
    int a; 
} 

Bạn có thể đọc về chủ đề này trong section 6.4 of the JLS, cùng với một số lý do.

3

Khối lambda một khối mới, còn gọi là phạm vi, nhưng nó không thiết lập bối cảnh/cấp độ mới, như triển khai lớp ẩn danh.

Từ Java Language Specification 15.27.2 Lambda Body:

Không giống như đang xuất hiện trong tờ khai lớp nặc danh, ý nghĩa của tên và thissuper từ khóa xuất hiện trong một cơ thể lambda, cùng với khả năng tiếp cận của tờ khai tham chiếu, là giống như trong bối cảnh xung quanh (ngoại trừ các thông số lambda giới thiệu tên mới).

Và từ JLS 6.4 Shadowing and Obscuring:

Những quy tắc cho phép khai báo lại của một biến hoặc địa phương lớp trong tờ khai lồng lớp (lớp địa phương (§14.3) và lớp nặc danh (§15.9)) xảy ra trong phạm vi của biến hoặc lớp địa phương. Do đó, việc khai báo một tham số chính thức, biến cục bộ hoặc lớp cục bộ có thể bị che khuất trong một khai báo lớp được lồng trong một phương thức, hàm tạo, hoặc biểu thức lambda; và việc khai báo một tham số ngoại lệ có thể bị che khuất bên trong một khai báo lớp được lồng trong khối của mệnh đề catch.

Có hai lựa chọn thiết kế để xử lý xung đột tên được tạo bởi tham số lambda và các biến khác được khai báo trong biểu thức lambda. Một là bắt chước các khai báo lớp: giống như các lớp địa phương, các biểu thức lambda giới thiệu một "mức" mới cho các tên và tất cả các tên biến bên ngoài biểu thức có thể được redeclared.Khác là chiến lược "cục bộ": như các mệnh đề bắt, đối với vòng lặp và khối, biểu thức lambda hoạt động ở cùng một mức "" như bối cảnh kèm theo và các biến cục bộ bên ngoài biểu thức không thể bị che khuất. Các quy tắc trên sử dụng chiến lược địa phương; không có sự phân biệt đặc biệt nào cho phép một biến được khai báo trong một biểu thức lambda để che một biến được khai báo trong một phương thức kèm theo.

Ví dụ:

class Test { 
    private int f; 
    public void test() { 
     int a; 
     a = this.f;  // VALID 
     { 
      int a;  // ERROR: Duplicate local variable a 
      a = this.f; // VALID 
     } 
     Runnable r1 = new Runnable() { 
      @Override 
      public void run() { 
       int a;   // VALID (new context) 
       a = this.f;  // ERROR: f cannot be resolved or is not a field 
           // (this refers to the instance of Runnable) 
       a = Test.this.f; // VALID 
      } 
     }; 
     Runnable r2 =() -> { 
      int a;  // ERROR: Lambda expression's local variable a cannot redeclare another local variable defined in an enclosing scope. 
      a = this.f; // VALID 
     }; 
    } 
} 
+0

vậy tại sao họ đưa ra quyết định này, là có một hạn chế có nghĩa là họ không thể, hoặc một lợi ích của họ không làm như vậy, tức là không có một mức độ mới của phạm vi cho mỗi lambda? – Tranquility

Các vấn đề liên quan