2011-11-11 41 views
10

Tôi cần phải khởi tạo một tập hợp các vals, trong đó mã để khởi tạo chúng có thể ném một ngoại lệ. Tôi muốn viết:Khởi tạo các vals có thể ném một ngoại lệ

try { 
    val x = ... generate x value ... 
    val y = ... generate y value ... 
} catch { ... exception handling ... } 

... use x and y ... 

Nhưng điều này (rõ ràng) không hoạt động vì x và y không nằm ngoài phạm vi thử.

Thật dễ dàng để giải quyết vấn đề bằng cách sử dụng các biến có thể thay đổi:

var x: Whatever = _ 
var y: Whatever = _ 
try { 
    x = ... generate x value ... 
    y = ... generate y value ... 
} catch { ... exception handling ... } 

... use x and y ... 

Nhưng đó không hẳn là rất tốt đẹp.

Nó cũng dễ dàng để giải quyết vấn đề bằng cách sao chép các xử lý ngoại lệ:

val x = try { ... generate x value ... } catch { ... exception handling ... } 
val y = try { ... generate y value ... } catch { ... exception handling ... } 

... use x and y ... 

Nhưng điều đó liên quan đến việc sao chép các xử lý ngoại lệ.

Phải có một cách "đẹp", nhưng nó đang cản trở tôi.

+1

Có thể bạn khai thác thực tế là các vals lười sẽ tính lại giá trị của chúng vào lần truy cập tiếp theo nếu ngoại lệ được ném trong khi khởi tạo chúng? – soc

Trả lời

5

Một giải pháp đơn giản là xác định hàm bao bọc sử dụng thông số tên.

def safely[T](f: => T): T = try { f } catch { /* exception handling */ } 
// You'll have to play around with safely's type signature, depending on what 
// you do in the exception handling 
val x = safely { generateX } 
val y = safely { generateY } 

Hoặc, nếu bạn cảm thấy thực sự khoe khoang, Scala 2.9 cho phép sử dụng một phần chức năng xử lý ngoại lệ.

val handler: PartialFunction[Throwable, Unit] = { /* exception handling */ } 
val x = try { generateX } catch handler 
val y = try { generateY } catch handler 

Nói chung, tôi sẽ nói rằng phương pháp đầu tiên là đơn giản nhất. Nhưng nếu bạn có thể viết các bit có thể sử dụng lại của các trình xử lý ngoại lệ có thể được kết hợp với nhau bằng cách sử dụng orElse hoặc andThen, thì phương pháp thứ hai sẽ thích hợp hơn.

9

Làm thế nào về khớp mẫu?

val (x, y) = try generateX -> generateY catch { /*exception handling*/ } 

hoặc

val (x, y) = try (generateX, generateY) catch { /*exception handling*/ } 
+0

Bạn không cần 'Số'. –

+0

Thx, đã sửa nó ... – agilesteel

+2

Đây là một trong những tình huống mà tôi muốn SO cho phép nhiều câu trả lời được chấp nhận. Tôi đã chấp nhận câu trả lời của dave, vì nó gần nhất với những gì tôi đã sử dụng, nhưng tất cả đều là những cách tiếp cận tốt. Cảm ơn! –

7

câu trả lời agilesteel là tốt nếu bạn chỉ muốn bắt bất kỳ ngoại lệ đó là ném và làm điều gì đó về thủ tục trong khối catch. Tuy nhiên, bạn có thể muốn xử lý riêng từng trường hợp ngoại lệ, trong trường hợp này bạn có thể cân nhắc tạo các loại của mình là Option hoặc Either.

Cách tích hợp để thực hiện việc này là với đối tượng Catch. Xem Exception docs.

Cách bạn sử dụng nó sẽ tùy thuộc vào những gì bạn muốn xảy ra khi ngoại lệ xảy ra. Ví dụ

import util.control.Exception.allCatch 

def handleInfinities(n: Int) = { 
    val x = allCatch.either { 100/n }  // Either[Throwable, Int] 
    val y = allCatch.either { 100/(n - 1) } 

    Seq(x, y) map { case Left(_) => Int.MaxValue; case Right(z) => z } 
} 

Sau đó handleInfinities(1) cho Thông báo

Seq[Int] = List(100, 2147483647) 

cách tập biến và xử lý các trường hợp ngoại lệ hiện nay là hoàn toàn tách biệt.

+0

Đây là một trong những tình huống mà tôi muốn SO cho phép nhiều câu trả lời được chấp nhận. Tôi đã chấp nhận câu trả lời của dave, vì nó gần nhất với những gì tôi đã sử dụng, nhưng tất cả đều là những cách tiếp cận tốt. Cảm ơn! –

1
import util.control.Exception._ 
def handler[A]: Catch[A] = handling(classOf[Exception]) by exceptionHandlingFunc 
val x = handler[X] apply { generateX } 
val y = handler[Y] apply { generateY } 
Các vấn đề liên quan