2016-09-28 7 views
1

私はスカラーレイジービューで遊んでいます。変換中に例外が発生した場合、処理するのは非常に簡単ではないようです。 は私がしようとラップしようとしたが、運と:レイジービュー変換での例外の処理

var v = (1 to 10).view.map { 
    case 5 => throw new Exception("foo") 
    case v => v 
} 

val w = v.map { w => Try(w) } 

w.foreach { x => 
    if (x.isFailure) 
    println("got it") 
    else 
    println(x.get) 
} 

結果:

v: scala.collection.SeqView[Int,Seq[_]] = SeqViewM(...) 

w: scala.collection.SeqView[scala.util.Try[Int],Seq[_]] = SeqViewMM(...) 

1 
2 
3 
4 
java.lang.Exception: foo 
    at #worksheet#.$anonfun$1.apply$mcII$sp(tt.sc0.tmp:4) 
    at #worksheet#.$anonfun$1.apply(tt.sc0.tmp:3) 
    at #worksheet#.$anonfun$1.apply(tt.sc0.tmp:3) 
    at scala.collection.TraversableViewLike$Mapped$$anonfun$foreach$2.apply(tt.sc0.tmp:165) 
    at scala.collection.Iterator$class.foreach(tt.sc0.tmp:889) 
    at scala.collection.AbstractIterator.foreach(tt.sc0.tmp:1332) 
    at scala.collection.IterableLike$class.foreach(tt.sc0.tmp:68) 
    at scala.collection.SeqLike$$anon$2.foreach(tt.sc0.tmp:667) 
    at scala.collection.TraversableViewLike$Mapped$class.foreach(tt.sc0.tmp:164) 
    at scala.collection.SeqViewLike$$anon$3.foreach(tt.sc0.tmp:193) 
    at scala.collection.TraversableViewLike$Mapped$class.foreach(tt.sc0.tmp:164) 
    at scala.collection.SeqViewLike$$anon$3.foreach(tt.sc0.tmp:193) 
    at #worksheet#.#worksheet#(tt.sc0.tmp:8) 

私は何をしないのですか?

答えて

1

あなたは何も欠けていません。それがビューのデザイン方法です。彼らはlazily例外をスローするメソッドを呼び出すが、単にの結果をとし、それを次のマップのメソッドに渡す。例外については何もするのは遅すぎます。結果を返す前に制御フローから抜け出してしまいます。

あなたは本当にこのような状況に対処する必要がある場合は、物事を行うことができますイテレータを使用して、手動でTrynext呼び出しをラップすることによりでもlazier。 (実装に応じて、あなたはまた、フィルターが除外される何かで例外をスローする可能性インスタンス--for hasNextをラップする必要があるかもしれません。)

val wb = Seq.newBuilder[Try[Int]] 
val vi = v.iterator 
while (vi.hasNext) wb += Try{ vi.next } 
val w = wb.result 

そうでない場合は、あなたが失敗したことを示すために、あなたのビューを再設計することができた場合失敗を示す値(例えば、Right(yay)が良い値であるLeft(ohDear)、または単にOptionを使用する)を返すことによって、よりスムーズに動作します。

あなたはwレベルで怠惰を維持したい場合は、そのようにそれを実装してみてください。

val vi = v.iterator 
val w = Iterator.continually(Try(vi.next)).takeWhile(_ => vi.hasNext) 

または単にTryブロックで危険なイテレータへの呼び出しをラップするカスタムイテレータを書きます。

+0

ありがとうございました!今すぐ明白に聞こえる... 最後を終了し、私はあなたの最後の提案を実装しました(カスタムイテレータを試してnext())。魅力的な作品 – mathieu

0

レイジービューを使用すると、consumerが消費されるまで、基礎となるイテレータが評価されないことがあります。 mapflatMapなどは消費者ではなく、transformerで、lazy viewを別のlazy viewに変換します。

消費者にはforeachfoldなどが含まれます。消費者がビューを消費する場合のみ、実際の変換ステップが実行されます。だから、あなたは自分のTryTry

val v = (1 to 10).view.map { 
    case 5 => throw new Exception("foo") 
    case v => v 
} 

val w = v.map(_ + 10) 

Try(w.foreach(i => 
    println(i) 
)) match { 
    case Success(_) => println("Successfully done.") 
    case Failure(ex) => println("I tried so hard... but it doesn't even matter") 
} 

そして...事に呼び出す消費ラップする必要がありますが、それはすべての可能な例外を守るように、それに問題のあるクリエイターを包むことになっている、ということです。実際に行うべきことは、変換をTryでラップすることです。

val view1 = (1 to 10).view 

val view2 = view1.map(v => Try(v match { 
    case 5 => throw new Exception("foo") 
    case v => v 
})) 

// Now, your view2 is actually a view of Try's 

// you can map it to transform again 

val view3 = view2.map({ 
    case Success(v) => v + 20 
    case Failure(ex) => throw ex 
}) 

// now consume 

view3.foreach({ 
    case Success(v) => println(v) 
    case Failure(ex) => println("this one is a bad boy") 
})