2010-11-24 19 views
8

İstisnaları kaydeden ve devam ettiren bir try-catch bloğuyla istisnalar atabilecek bir kod yazmak istiyorum. gibi bir şey: İdealScala'da "this" kelimesini implicit parametresi olarak vermek mümkün mü?

loggingExceptions { 
    // something dangerous 
} 

, ben eğer herhangi biri (ve hiçbiri bir derleme zamanı hatası alırsanız), çağıran nesne üzerinde tanımlı Logger giriş için kullanmak istiyorum. Böyle bir şey tanımlamak isteriz:

def loggingExceptions[L <: { def logger: Logger }](work: => Unit)(implicit objectWithLogger: L): Unit = { 
    try { 
    work 
    } catch { 
    case t: Exception => objectWithLogger.logger.error(t.getMessage) 
    } 
} 

objectWithLogger bir şekilde "sihirli" "Bu" istemci kod genişletmek vermesi. Bu (veya benzer bir şey) mümkün mü?

cevap

11

istediğiniz gibi. Diğer cevap verenler çok hızlı bir şekilde teslim oldular. Beyaz bayrak yok!

package object foo { 
    type HasLogger = { def logger: Logger } 
    implicit def mkLog(x: HasLogger) = new { 
    def loggingExceptions(body: => Unit): Unit = 
     try body 
     catch { case ex: Exception => println(ex) } 
    } 
} 

package foo { 
    case class Logger(name: String) { } 

    // Doesn't compile: 
    // class A { 
    // def f = this.loggingExceptions(println("hi")) 
    // } 
    // 1124.scala:14: error: value loggingExceptions is not a member of foo.A 
    //   def f = this.loggingExceptions(println("hi")) 
    //     ^
    // one error found 

    // Does compile 
    class B { 
    def logger = Logger("B") 
    def f = this.loggingExceptions(println("hi")) 
    def g = this.loggingExceptions(throw new Exception) 
    } 
} 

object Test { 
    def main(args: Array[String]): Unit = { 
    val b = new foo.B 
    b.f 
    b.g 
    } 
} 

// output 
// 
// % scala Test 
// hi 
// java.lang.Exception 
+2

+1. Bu _can_ yapılabilir, ama bu tavsiye edilmez. Kayıt kaygısının yanı sıra günlüğe kaydetme özelliğini ayırmaz, "örtülü sihir" gerektirir ve gereksiz derleme zamanına (örtülü arama) ve çalışma zamanı (yansıma) yüküne neden olur. Uygulama, örtülü dönüşümün kapsam dahilinde olması gerektiğini ve daha gerçekçi bir kod tabanında, bu, müşteri kodunda bir içe aktarım ifadesi gerektireceğini gizler. –

+4

Negatifler listenizin listesi "Farklı bir problemi çözmeyi tercih ederim." Evet, hepimiz olmazdık. – extempore

+0

Gerçekten değil. Temel sorun, bir kayıt defterine sahip bir sınıftaki bir kod bloğundaki istisnaları günlüğe kaydetmektir. Bu problemi, OP'nin ilk bakışta öngördüğü şekilde (dolaylı olarak) çözebilir ya da bir özelliği daha basit bir şekilde çözebilirsiniz. –

3

def loggingExceptions kullanmak istediğiniz tüm sınıflara bir özellik ekleyebilir ve bu özelliğin içinde def logger: Logger kullanılabilir olmasını bekleyen bir kendim türü ekleyebilirsiniz.

trait LoggingExceptions { 
    this: { def logger: Logger } => 
    def loggingExceptions(work: => Unit) { 
    try { work } 
    catch { case t: Exception => logger.error(t.getMessage) } 
    } 
} 

object MyObjectWithLogging extends OtherClass with LoggingExceptions { 
    def logger: Logger = // ... 

    def main { 
    // ... 
    loggingExceptions { // ... 
    } 
    } 
} 
+0

Teşekkürler, bu işe yarıyor! Fakat loggingExceptions (...) kullanmak isteyen tüm sınıfların bildirimlerini değiştirmeyi gerektirmeyen başka çözümler var mı? –

+0

@JPP Hayır, en azından, arama alanının kapsamdaki beklenen türün örtülü bir nesnesine sahip olması gerekir. Örneğin, örtülü parametreyi 'Logger' yapabilir ve çağıran nesnede 'def logger'ı' implicit def logger 'olarak değiştirebilirdiniz. Bununla birlikte, gerekmedikçe örtüklerden kaçınılmalı ve bir özellik bu sorun için iyi bir uyumdur. Örnek için –

4

Debilski's answer çalışacaktır, ama ben (yani { def logger: Logger }) burada bir yapısal tipini kullanmak için iyi bir neden görmüyorum emin değilim. Yapısal tiplerin uygulanması, yansımaya dayanması nedeniyle, logger çağrıldığında ekstra çalışma zamanı yükü gerektirecektir. loggingExceptions yöntem yakından günlük bağlıdır, bu yüzden sadece bir Günlüğü özelliğin bir parçası yapacak: Aslında yapılabilir

trait Logging { 
    def logger: Logger 

    final def loggingExceptions(body: => Unit) = 
     try body catch { case e: Exception => logger.error(e.getMessage) } 
} 

trait ConcreteLogging extends Logging { 
    val logger = // ... 
} 

object MyObject extends SomeClass with ConcreteLogging { 
    def main { 
     // ... 
     loggingExceptions { 
     // ... 
     } 
    } 
} 
İlgili konular