2010-05-24 26 views
11

Theo như tôi được biết, không có cách nào trong Scala có nhiều điểm trở lại trong một chức năng ẩn danh, ví dụ:Nhiều điểm trở lại trong scala đóng/chức năng ẩn danh

someList.map((i) => { 
    if (i%2 == 0) return i // the early return allows me to avoid the else clause 
    doMoreStuffAndReturnSomething(i) // thing of this being a few more ifs and returns 
}) 

đặt ra một error: return outside method definition. (Và nếu nó không được huy động đó, mã sẽ không làm việc như tôi muốn nó để làm việc.)

Một workaround tôi có thể điều của sẽ là sau

someList.map({ 
    def f(i: Int):Int = { 
     if (i%2 == 0) return i 
     doMoreStuffAndReturnSomething(i) 
    } 
    f 
}) 

tuy nhiên, tôi Tôi muốn biết nếu có một cách khác được chấp nhận để làm điều này. Có lẽ một khả năng để đi mà không có một tên cho chức năng bên trong?

(Một trường hợp sử dụng sẽ bắt chước một số giá trị continue cấu trúc bên trong vòng lặp.)

Sửa

Hãy tin tôi, rằng có một nhu cầu để tránh những tuyên bố khác, bởi vì, các doMoreStuff phần thực sự có thể trông giống như:

val j = someCalculation(i) 
if (j == 0) return 8 
val k = needForRecalculation(i) 
if (k == j) return 9 
finalRecalc(i) 
... 

đó, khi bạn chỉ có một if - Cơ cấu else sẵn được e lộn xộn.

Tất nhiên, trong ví dụ đơn giản tôi đã đưa ra ở đầu, nó dễ dàng hơn để chỉ sử dụng else. Xin lỗi, tôi nghĩ điều này rõ ràng.

+0

Sự cố khi sử dụng câu lệnh khác là gì? – Patrick

+1

Trong ví dụ bạn đưa ra không có lý do gì cả để tránh từ khóa 'else'; không có biểu thức bổ sung nào được đánh giá nếu bạn sử dụng 'else', vì vậy bạn không có gì bằng cách sử dụng trả lại sớm ở đây. – Jesper

+0

Xin lỗi, tôi đã sửa đổi nó. Nghĩ rằng rõ ràng phần 'doMoreStuff' thực sự * làm * nhiều hơn một chút. – Debilski

Trả lời

1

Tôi nghĩ rằng vấn đề chính với các điểm trả về trong các chức năng ẩn danh là một hàm ẩn danh có thể xuất hiện ở một nơi mà người ta thường không mong đợi. Vì vậy, nó sẽ không được rõ ràng mà đóng cửa tuyên bố trở lại thực sự sẽ thuộc về. Vấn đề này được giải quyết bằng cách yêu cầu rõ ràng một sự tương ứng def - return*.

Cách khác, người ta cần có người bảo vệ xung quanh tuyên bố để từ đó trở về. breakable - break nhưng rất tiếc là không thể trả lại giá trị đó. Một số giải pháp dựa trên tiếp tục sẽ có thể đạt được mục tiêu đó, mặc dù tôi muốn chờ đợi một số chấp nhận chung và các thư viện ở đó.

5

Nếu hàm ẩn danh của bạn phức tạp, tôi sẽ làm cho nó rõ ràng hơn. Các hàm ẩn danh không phù hợp với bất kỳ điều gì phức tạp hơn một vài dòng. Bạn có thể đặt phương thức đó ở chế độ riêng tư bằng cách khai báo nó trong phương thức sử dụng

def myF(i:Int):Int = { 
    if (i%2 == 0) return i 
    doMoreStuffAndReturnSomething(i) 
} 
someList.map(myF(_)) 

Đây là một biến thể trong cách giải quyết của bạn, nhưng sạch hơn. Cả hai đều giữ riêng tư cho phạm vi phương thức cục bộ.

+0

Đây là giải pháp tuyệt vời. Tôi là một scala newb vì vậy tôi không thực sự hiểu tại sao điều này là cần thiết, nhưng nó giải quyết được vấn đề. – ripper234

3

Trong comment mã của bạn, bạn đã viết mà bạn muốn tránh những từ khóa else, nhưng IMHO này thực hiện chính xác những gì bạn muốn và thậm chí nó hai nhân vật ngắn hơn ;-)

someList.map((i) => { 
    if (i%2 == 0) i else 
    doMoreStuffAndReturnSomething(i) 
}) 
+0

Vui lòng xem chỉnh sửa của tôi. – Debilski

+0

Trên thực tế, tôi muốn nói rằng nó tiết kiệm nhiều hơn hai ký tự: Một 'return' rõ ràng buộc bạn phải khai báo kiểu trả về anyway ... Tuy nhiên, trường hợp sử dụng thực tế của tôi sẽ phức tạp hơn một chút so với ví dụ ban đầu của tôi. chỉ là về việc lưu các ký tự. – Debilski

3

Ví dụ bạn đã đưa ra dễ dàng được giải quyết bằng câu lệnh if. Không có hiệu suất hoặc các hình phạt khác để thực hiện việc này.

Nhưng bạn có thể có một số tình huống khác, trông gần giống như

if (test) { 
    if (anotherTest) { 
    val a = someComputation() 
    if (testOf(a)) return otherComputation() 
    } 
    else if (yetAnotherTest) return whatever() 
} 
bigComputation() 

Có một vài cách để đối phó với loại tình huống này nếu bạn muốn tránh những mớ if-báo cáo và/hoặc mã trùng lặp cần thiết để chuyển đổi hình thức này thành biểu mẫu mà không trả về.

Có những điều lén lút khác nhau mà bạn có thể làm với Option hoặc Either để giữ trạng thái chảy dọc (với orElsefold) để bạn làm chỉ là tính toán bạn cần.

Bạn thực sự tốt hơn khi tạo một def như bạn đề xuất.Nhưng chỉ để so sánh, hãy xem xét một Option-gói phong cách:

i => { 
    (if ((i%2)==0) Some(i) 
    else None 
).getOrElse(doStuffAndReturn(i)) 
} 

Trên dụ lớn trên, phong cách này sẽ cung cấp cho

(if (test) { 
    if (anotherTest) { 
     val a = someComputation() 
     if (testOf(a)) Some(otherComputation()) else None 
    } 
    else if (yetAnotherTest) Some(whatever()) 
    else None 
}).getOrElse(bigComputation()) 

Cá nhân, tôi không nghĩ rằng đó là rõ ràng hơn (và nó chắc chắn không nhanh hơn), nhưng có thể.

+0

Vâng, nó là phức tạp (hoặc thậm chí nhiều hơn một chút) như là ví dụ ban đầu mà không trả về. Nhưng tất nhiên đó là một cách tiếp cận hợp lệ trong các tình huống khác. – Debilski

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