2017-07-27 42 views
3

我有兩種方法,都爲Future [要麼[String,T]]返回並且想要將它們鏈接在一起以完成工作。我正在使用Scala 2.12要麼現在是有偏見的。Scala 2.12 Future和Either的組合(偏頗版本)

例如,

如果函數沒有返回未來,要麼組合,我可以簡單地不喜歡與理解以下。

def convert(a, b) = ??? 
def callA(): Future[A] = ??? 
def callB(a: A): Future[B] = ??? 

def chain: Future[C] = for { 
    a <- callA 
    b <- callB(a) 
} yield convert(a, b) 

但現在我想用下面的語法使用Either捕獲錯誤,並傳播到最終結果。達到這個目標的最好方法是什麼?還應該使用callB或callB1?

def convert(a, b): Future[Either[String, C]] = ??? 
def callA(): Future[Either[String, A]] = ??? 
def callB(a: A): Future[Either[String, B]] = ??? or 
def callB1(eithera: Either[String, A]): Future[Either[String, B]] = ??? 

我知道使用貓轉換monad可以簡化這一點。歡迎爲我提供使用標準庫和貓的解決方案。

+1

如果單純使用'Either' 'Left'返回一個'String',我假設它是一個包含錯誤的文本消息,爲什麼不簡單地使用'Future'中的'Success'和'Failure'? – Yaneeve

+2

猜你可能想看看'cats'或'scalaz'的'EitherT' – jilen

+0

@Yaneeve我只是想簡化一下,它實際上是一個自定義的錯誤對象。 – ttt

回答

5

正如評論所說,這是貓和斯卡拉可以處理的事情。但是我也可以理解,不要爲一小段邏輯引入另一個依賴或複雜性。這裏是,如果你想自己實現它,你能做些什麼:

implicit class FutureEither[A](val wrapped: Future[Either[String, A]])(implicit ec: ExecutionContext) { 
    def map[B](f: A => B): FutureEither[B] = wrapped.map(_.map(f)) 

    def flatMap[B](f: A => FutureEither[B]): FutureEither[B] = wrapped.flatMap { 
    case Left(s) => Future(Left(s)) 
    case Right(a) => f(a).wrapped 
    } 
} 

實施mapflatMap相應品種使完全相同的樣式,理解:

def convert(a: A, b: B): C = ??? 
def callA(): FutureEither[A] = ??? 
def callB(a: A): FutureEither[B] = ??? 

def chain: FutureEither[C] = for { 
    a <- callA() 
    b <- callB(a) 
} yield convert(a, b) 
+0

問題是我們如何將'FutureEither [C]'轉換回'Future [[String,C]]'?謝謝。 – ttt

+0

只要做'.wrapped' –