2013-07-25 28 views
21

Trong ví dụ dưới đây tôi nhận được ngoại lệ java.util.NoSuchElementException: Future.filter predicate is not satisfiedScala tương lai với bộ lọc trong cho sự hiểu biết

Tôi muốn có kết quả Future(Test2) khi kiểm tra if(i == 2) thất bại. Làm thế nào để xử lý bộ lọc/nếu trong một hiểu cho rằng giao dịch với tương lai soạn?

Dưới đây là một ví dụ đơn giản hóa hoạt động trong REPAL REPL.

Code:

import scala.concurrent.Future 
import scala.util.{ Try, Success, Failure } 
import scala.concurrent.ExecutionContext.Implicits.global 

val f1 = Future(1) 
val f2 = for { 
    i <- f1 
    if(i == 2) 
} yield "Test1" 
f2.recover{ case _ => "Test2" } 
f2.value 

Trả lời

11

Trong for-comprehension của bạn, bạn đang lọc theo i == 2. Bởi vì giá trị của f1 không phải là hai, nó sẽ không mang lại một số Success mà thay vào đó là Failure. Vị từ của bộ lọc không hài lòng, vì thông điệp errror của bạn cho bạn biết. Tuy nhiên, f2.recover trả về một Future mới. Giá trị của f2 không được điều khiển. Nó vẫn lưu trữ Failure. Đó là lý do bạn nhận được thông báo lỗi khi bạn gọi f2.value.

Cách thay thế duy nhất tôi có thể nghĩ là sử dụng else trong số for-comprehension như được hiển thị here.

val f2 = for (i <- f1) yield { 
    if (i == 2) "Test1" 
    else "Test2" 
} 
f2.value 

Điều này sẽ trả về Some(Success(Test2)) làm f3.value của bạn.

+0

Tuy nhiên nếu f2 thất bại vì "i <- f1" thất bại, kết quả sẽ không là "Test2" nhưng vẫn là lỗi. –

8

Dĩ nhiên tôi đã tìm ra một giải pháp bản thân mình. Có lẽ có giải pháp tốt hơn, thành ngữ hơn?

import scala.concurrent.Future 
import scala.util.{ Try, Success, Failure } 
import scala.concurrent.ExecutionContext.Implicits.global 

val f1 = Future(1) 
val f2 = for { 
    i <- f1 
    if(i == 2) 
} yield "Test1" 
val f3 = f2.recover{ case _ => "Test2" } 
// OR val f3 = f2.fallbackTo(Future("Test2")) 
f3.value 
+1

Nó được đề cập trong các tài liệu cũng như: http://docs.scala-lang.org/overviews/core/futures.html#functional_composition_and_forcomprehensions không khi tôi nhìn lại lần thứ hai. – Magnus

+1

Tôi nghĩ rằng việc sử dụng 'phục hồi' ở đây là không sao. Nếu bạn muốn phục hồi của bạn chỉ áp dụng cho ngoại lệ dựa trên biến vị ngữ bộ lọc, thì bạn nên thay đổi trường hợp 'case _' thành' case: NoSuchElementException' trong đó 'NoSuchElementException' xuất phát từ' java.util'. – cmbaxter

+0

Jürgen: Đây là câu hỏi sáu tháng tuổi, đoạn mã trên là một ví dụ được lấy ra từ phiên REPL, vì vậy nó hướng đến sự rõ ràng. Bạn đang bình luận về điều đó bạn có thể đặt dấu ngoặc đơn xung quanh các câu lệnh trong Scala? Không thấy những gì đóng góp của bạn là ở đây. – Magnus

27

Đây là giải pháp thành ngữ hơn, theo ý kiến ​​của tôi. Hàm biến vị ngữ này tạo ra một số Future[Unit] hoặc một tương lai không thành công có chứa ngoại lệ của bạn. Ví dụ của bạn, điều này sẽ dẫn đến hoặc là Success("Test1") hoặc Failure(Exception("Test2")). Điều này hơi khác với "Test1" và "Test2", nhưng tôi thấy cú pháp này hữu ích hơn.

def predicate(condition: Boolean)(fail: Exception): Future[Unit] = 
    if (condition) Future(()) else Future.failed(fail) 

Bạn sử dụng nó như thế này:

val f2 = for { 
    i <- f1 
    _ <- predicate(i == 2)(new Exception("Test2")) 
    j <- f3 // f3 will only run if the predicate is true 
} yield "Test1" 
+1

Đây là lời khuyên rất hữu ích. Cảm ơn! – Tommi

+0

Rõ ràng hơn rất nhiều, cảm ơn! – Artemis

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