2017-08-07 121 views
0

是否有隻包裝傳遞函數的返回類型的方法?如何在Scala中包裝傳遞函數的返回類型

我試圖自動使用自動管理資源try-with-resources scala equivalent。我想要做的是嵌套託管資源,即做類似的事情:

cleanly(db.connect())(_.close()) { connection => 
      cleanly(connection.prepareCall("{call procedure}"))(_.close()) { statement => 
       statement.setInt("batch", 1) 
       statement.execute() 
      } 
     } 

但是,返回Try [Try [B]]。所以我稍微修改了簽名和實施清潔功能:

def cleanly[A, B](resource: A)(cleanup: A => Unit)(doWork: A => Try[B]): Try[B] = { 
     try { 
      doWork(resource) 
     } 
     finally { 
      try { 
       if (resource != null) { 
        cleanup(resource) 
       } 
      } catch { 
       case e: Exception => log.error("Error cleaning up resource.", e) // should be logged 
      } 
     } 
    } 

我試着從一個新添加的方法tryCleanly這將包裹傳遞函數返回一個嘗試對象調用它:

def tryCleanly[A, B](resource: A)(cleanup: A => Unit)(doWork: A => B): Try[B] = { 
    cleanly[A,B](resource)(cleanup)(Try(doWork)) 
} 

但是做嘗試(的doWork)的結果

Try[(A) => B] 

而不是

(A) => Try[B] 

是否可以只包裝函數的結果類型?

回答

1
def tryCleanly[A, B](resource: A)(cleanup: A => Unit)(doWork: A => B): Try[B] = { 
    cleanly[A,B](resource)(cleanup)(a: A => Try(doWork(a))) 
} 
0

您可以將flattenTry[Try[B]]設置爲Try[B]。例如:

val try1 = Try(Try(3)) // Try[Try[Int]] 
val try2 = try1.flatten // Try[Int] 

解開任意深度的嵌套Try,您可以採用如下方案(我借這個解決方案從這個answer,功勞都到@SarveshKumarSingh):

import scala.language.higherKinds  

case class Flattener[W[_], WW, T](fn: WW => W[T]) 

implicit def tryRecursiveFlattenFn[WW, T](
    implicit f: Flattener[Try, WW, T] = Flattener((ww: WW) => Try(ww)) 
) = Flattener((ww: Try[WW]) => ww.flatMap(f.fn)) 

def tryRecursiveFlatten[WW, T](www: Try[WW])(
    implicit f: Flattener[Try, Try[WW], T] 
) = f.fn(www) 

val try1 = Try(Try(Try(Try(3)))) // Try[Try[Try[Try[Int]]]] 
val try2 = tryRecursiveFlatten(try1) // Try[Int] 
+0

沒錯,但我想的是更多的一元風格。如果我擁有兩個以上的嵌套資源,那麼我將需要多次調用flatten,這並不理想 – user3681304

0

@JoeK激勵我再次混淆參數,所以學分歸他所有。我最終得到的是這樣的:

def cleanly[A, B](resource: A)(cleanup: A => Unit)(doWork: A => Try[B]): Try[B] = { 
    try { 
     doWork(resource) 
    } 
    finally { 
     try { 
      if (resource != null) { 
       cleanup(resource) 
      } 
     } catch { 
      case e: Exception => log.error("Error cleaning up resource.", e) // should be logged 
     } 
    } 
} 

def tryCleanly[A, B](resource: A)(cleanup: A => Unit)(doWork: A => B): Try[B] = { 
    cleanly[A,B](resource)(cleanup)(resource => Try(doWork(resource))) 
}