2017-06-09 2 views
2

私はScalaに新たなんだとそれは単に非致命的な例外をキャッチTry::applyTryで最後にすることはできますか?

def apply[T](r: => T): Try[T] = 
    try Success(r) catch { 
    case NonFatal(e) => Failure(e) 
    } 

のソースコードを見ました。しかし、私はfinally節が必要な場合はどうしますか?機能的にはTryでエミュレートすることは可能ですか?私は

Try{ 
    //acquire lock 
    //do some 
} 
//Now how to release? 

答えて

4

try{ 
    //acquire lock 
    //do some 
} finally { 
    // release lock 
} 

のようなものTryが値に解決し、何かが失敗したとき、それはスタックをアンワインドしないのでTryが実行された後、あなたは、単にクリーンアップ操作を実行できることを意味します。たとえば、次のように

val someLock = ??? // acquire some lock 
val result = Try { 
    // do something and return a result 
} 
someLock.release() 

ご希望の場合は、単一の式にすべてを保つために、独自のヘルパーをロールバックすることができます:

def withLock[A](f: Lock => A): Try[A] = { 
    val lock = ??? // acquire the lock 
    val res = f(lock) 
    lock.release() 
} 

をして、あなたが書くことができます。

val res = withLock { lock => 
// some operation 
} 

これは、通常ローンパターンと呼ばれます。

+0

なぜf:Lock => Aですか?なぜあなたが外部でそれを取得している場合、関数にロックを渡す?サンクがやる名前のように思える?ロックの場合は 'f:=> A' –

+0

、そうでしょう。パターンは、 'ブロック'の内部で使用される必要のある接続のようなものによく適合します。 –

2

すでに似たようなものがありましたhere

TLTR; Tryモナドで標準的な方法はありません。

通常の回避策は、このようなものです:あなたは次のように使用することができます

def use[A <: { def close(): Unit }, B](resource: A)(code: A ⇒ B): B = 
    try { 
     code(resource) 
    } finally { 
     resource.close() 
    } 

val path = Paths get "/etc/myfile" 
use(Files.newInputStream(path)) { inputStream ⇒ 
    val firstByte = inputStream.read() 
    .... 
} 

hereを説明されている別のアプローチを、あなたは標準の「トライ」を「伸ばす」ことを意味し追加のメソッド 'withRelease'を追加することにより、追加されます。

implicit class TryOps[A <: { def close(): Unit }](res: Try[A]) { 
    def withRelease() = res match { 
    case Success(s) => res.close(); res 
    case Failure(f) => res.close(); res 
    } 
} 

Th en、

Try { 
    val inputStream = Files.newInputStream(path)) 
    ... 
    inputStream 
}.withRelease() 
関連する問題