2012-04-11 41 views
7

Tôi thấy mình lặp lại các khối try/catch đơn giản nên, IMO, là 1 lớp lót.Scala DRYing try/catch

Ví dụ: giả sử tôi cần chuyển đổi ngày chuỗi uri theo định dạng yyyymmdd thành Joda-Time. Với try/catch chuẩn chặn các phương pháp chuyển đổi trông giống như:

def ymd2Date(ymd: Option[String]) = ymd match { 
    case Some(date) => 
    try { Right(ymdFormat.parseDateTime(date)) } 
    catch { case e => 
     log.info(e.getMessage) 
     Left(None) 
    } 
    case None => 
    Left(None) // no uri date param 
} 
val ymdFormat = DateTimeFormat.forPattern("yyyyMMdd") 

trình cũng đủ, ý định là rõ ràng, nhưng khi tôi làm điều này loại try/catch đăng nhập cho tất cả sự kiện không quan trọng, sau đó tôi tìm cách để làm khô nó. Tìm kiếm đã dẫn tôi đến điều này SO post trên scala.util.control.Exception. Hữu ích, nhưng nó vẫn còn một chút khó khăn để grok/làm cho nó hoạt động theo cách tôi muốn nó. Trong tiếng Anh đơn giản, tôi chỉ muốn nói, "nắm bắt một số loại lỗi nhật ký kết quả nhận được một hành động".

Vì vậy, tôi bị hack ra này dựa trên một phần của control.Exception Tôi quan tâm đến (hoặc hiểu là hữu ích):

class Catcher[T](f: => T) { 
    type Logger = (=> Any) => Unit 

    def either[T](logger: => Logger) = { 
    try { Right(f) } 
    catch { case e => 
     logger(e.getMessage) 
     Left(None) 
    } 
    } 
} 
def catching[T](f: => T) = new Catcher(f) 

Và sau đó sử dụng ở vị trí của try/catch như vậy:

catching(ymdFormat.parseDateTime(date)) either log.info 

thể thêm vào tùy chọn, một tiền tố msg, vv, nhưng ... nó có lẽ sẽ tốt hơn để tìm một cách để có được control.Exception để làm việc như trên, khi đoàn làm phim typesafe sẽ tạo ra thế giới mã tốt hơn tôi tưởng tượng bằng văn bản.

Có ai biết cách tạo loại cú pháp này bằng cách sử dụng control.Exception nơi người ta có thể chuyển vào một hàm logger theo tên được sử dụng trong khối catch không?

Sẽ là tuyệt vời nếu có là một "trường hợp sử dụng" cho control.Exception, nhưng tôi nhận được cảm giác tiện ích này là dành cho nâng cao hơn devs Scala

+3

Tại sao bạn sử dụng 'Either'? Nếu tất cả các bạn sẽ đặt vào 'Left' là' None', thì có vẻ như bạn có thể sử dụng 'Option [T]'. – huynhjl

+0

điểm tốt, tôi muốn gấp hơn kết quả và có vẻ giống như một sự phù hợp tự nhiên ... – virtualeyes

+0

mà là để nói, hiện tại không có lựa chọn gấp, hoặc ít nhất không được xây dựng vào ngôn ngữ – virtualeyes

Trả lời

7

này nên làm những gì bạn muốn:

import scala.util.control.Exception 
def log(logger: => Logger)(e: Throwable) = { 
    logger(e.getMessage) 
    None 
} 
Exception.allCatch withApply log(logger) apply Some(ymdFormat.parseDateTime(date)) 

Nhưng loại công cụ này được xử lý tốt hơn bằng cách Scalaz Validation, theo ý kiến ​​của tôi.

+0

phải, chưa mạo hiểm xuống hàng Scalaz, chỉ cần chân tôi bị ướt trong Scala. Xác nhận ở dạng cơ bản nhất của nó trông giống như một trong hai, nhưng sau đó đường cong ratchets lên một cách nhanh chóng. Đó là trên công việc phải làm ... – virtualeyes

+0

đó là khá mát mẻ, btw, trông giống như tôi có thể phế liệu hack của tôi và có một cách tiếp cận mà một ai đó khác hơn bản thân mình sẽ hiểu ;-) – virtualeyes

+2

@virtualeyes - Đối với những gì nó có giá trị, "hack" của bạn là rõ ràng hơn với tôi hơn cách tiếp cận của Daniel (sẽ được rõ ràng hơn nếu bạn không gọi nó là "bắt" nhưng thay vì 'tryOrLog' hoặc cái gì đó không cho rằng đối số đầu tiên sẽ tự nó bị bắt). –

3

Một ví dụ nhanh:

import scala.util.control.Exception._ 

def throwingStuff { 
    throw new Exception("Hello World!") 
} 

catching(classOf[Exception]).withApply{err => println(err.toString); None}.apply(Some(throwingStuff)) 

Bạn có thể sử dụng withApply để ghi đè lên logic ứng dụng của lớp Catch để làm điều gì đó như ghi vào nhật ký.

+0

Kiểu trả về không hoàn toàn làm việc với điều này. 'withApply' chuyển đổi' Throwable' thành một giá trị trả về, vì vậy bạn sẽ không bao giờ có 'Left', và' Right''s type sẽ là 'Any' hoặc' AnyRef'. –

+0

Đúng, nhận ra và chỉnh sửa ngay trước bình luận của bạn! Tuy nhiên, sử dụng 'Some' là một ý tưởng hay. – Submonoid

+0

Cần bảo quản loại. Nếu tôi chọn Tùy chọn [T] thì loại có được lưu giữ/truy cập không? – virtualeyes