2010-11-24 12 views
8

मान लीजिए कि मैं कोड को लपेटना चाहता हूं जो अपवाद को लॉग इन करने वाले प्रयास-चिह्न ब्लॉक के साथ अपवाद फेंक सकता है और जारी रहता है। की तरह कुछ:क्या स्कैला में अंतर्निहित पैरामीटर के रूप में "यह" पास करना संभव है?

loggingExceptions { 
    // something dangerous 
} 

आदर्श रूप में, मैं, लॉगर बुला वस्तु पर परिभाषित प्रवेश करने के लिए उपयोग करना चाहते हैं, यदि कोई हो (और कोई नहीं, एक संकलन समय त्रुटि मिलती है)। मैं कुछ इस तरह परिभाषित करने के लिए खुशी होगी:

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

जहां objectWithLogger किसी भी तरह "जादुई" से "इस" ग्राहक में कोड का विस्तार होगा। क्या यह (या एक समान चीज़) संभव है?

उत्तर

11

यह वास्तव में किया जा सकता है आप चाहते हैं बस के रूप में। अन्य उत्तरदाताओं ने बहुत जल्दी आत्मसमर्पण कर दिया। कोई सफेद झंडे नहीं!

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। यह _can_ किया जाना चाहिए, लेकिन यह अव्यवस्थित है। यह लॉगिंग चिंता के साथ-साथ लॉगिंग विशेषता को अलग नहीं करता है, इसके लिए "अंतर्निहित जादू" की आवश्यकता होती है, और अनावश्यक संकलन-समय (अंतर्निहित खोज) और रन-टाइम (प्रतिबिंब) ओवरहेड होता है। कार्यान्वयन इस तथ्य को छुपाता है कि अंतर्निहित रूपांतरण को दायरे में होना चाहिए, और अधिक यथार्थवादी कोडेबेस में इसे क्लाइंट कोड में आयात विवरण की आवश्यकता होगी। –

+4

नकारात्मकों की आपकी सूची "मैं एक अलग समस्या को हल करने की बजाय" बताती हूं। खैर हाँ, हम सब नहीं करेंगे। – extempore

+0

वास्तव में नहीं। मौलिक समस्या उस वर्ग के भीतर कोड के ब्लॉक में अपवाद लॉगिंग कर रही है जिसमें लॉगजर है। आप उस समस्या को हल कर सकते हैं जिस तरह ओपी ने मूल रूप से कल्पना की थी (implicits के साथ), या आप इसे एक विशेषता के साथ और अधिक हल कर सकते हैं। –

3

आप सभी कक्षाओं में एक विशेषता जोड़ सकते हैं जो def loggingExceptions का उपयोग करना चाहते हैं और इस विशेषता में एक स्व-प्रकार जोड़ें जो def logger: Logger उपलब्ध होने की अपेक्षा करता है।

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

धन्यवाद, यह काम करता है! लेकिन क्या ऐसे कोई अन्य समाधान हैं जिनमें लॉगिंग अपवाद (...) का उपयोग करने के इच्छुक सभी वर्गों की घोषणा को शामिल नहीं करना शामिल है? –

+0

@ जेपीपी संख्या, कम से कम कॉलसाइट को अपेक्षित प्रकार के दायरे में एक अंतर्निहित वस्तु की आवश्यकता होगी। उदाहरण के लिए, आप अंतर्निहित पैरामीटर को 'लॉगर' बना सकते हैं, और कॉलिंग ऑब्जेक्ट में 'def logger' को' implicit def logger' में बदल सकते हैं। हालांकि, जरूरी होने तक निहितार्थों से बचा जाना चाहिए, और इस समस्या के लिए एक विशेषता उपयुक्त है। उदाहरण के लिए –

4

Debilski's answer काम करेंगे, लेकिन मुझे यकीन है कि मैं यहाँ (अर्थात { def logger: Logger }) एक संरचनात्मक प्रकार का उपयोग करने के लिए एक अच्छा कारण देख नहीं हूँ। जब भी logger लागू होता है, तो ऐसा करने से अतिरिक्त रनटाइम ओवरहेड लग जाएगा, क्योंकि संरचनात्मक प्रकार के कार्यान्वयन प्रतिबिंब पर निर्भर करता है। loggingExceptions विधि बारीकी से प्रवेश से जुड़ा हुआ है, तो मैं बस यह एक लॉगिंग विशेषता का हिस्सा बनाना होगा:

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 { 
     // ... 
     } 
    } 
} 
संबंधित मुद्दे

 संबंधित मुद्दे