2013-05-07 6 views
15

क्या मैं एक विधि को चालू कर सकता हूं जो किसी फ़ंक्शन में अंतर्निहित पैरामीटर लेता है?आंशिक रूप से एक फ़ंक्शन को लागू करना जिसमें अंतर्निहित पैरामीटर

trait Tx 

def foo(bar: Any)(implicit tx: Tx) {} 

foo _ // error: could not find implicit value for parameter tx: Tx 

मैं अधिमानतः अगर मैं किसी भी तरह यह स्पष्ट कॉल withSelection(deleteObjects) के साथ काम कर सकते हैं, निम्नलिखित प्राप्त करने के लिए कोशिश कर रहा हूँ: हालांकि इसके साथ सौदा नहीं है

trait Test {  
    def atomic[A](fun: Tx => A): A 

    def selection: Iterable[Any] 

    def withSelection(fun: Iterable[Any] => Tx => Unit) { 
    val sel = selection 
    if (sel.nonEmpty) atomic { implicit tx => 
     fun(sel)(tx) 
    } 
    } 

    object deleteAction { 
    def apply() { 
     withSelection(deleteObjects) // ! 
    } 
    } 

    def deleteObjects(xs: Iterable[Any])(implicit tx: Tx): Unit 
} 

मैं this question पाया, जहां तक ​​मैं देख सकता हूं विधियों से कार्य करने के लिए।

उत्तर

6

इम्प्लिकेट केवल विधियों के लिए काम करते हैं। लेकिन आपको withSelection पर फ़ंक्शन पास करना होगा। आप एक समारोह में विधि लपेटकर द्वारा आसपास पहुंच सकते हैं:

withSelection(a => b => deleteObjects(a)(b)) 

इसकी असंभव पारित करने के लिए deleteObjects सीधे क्योंकि foo _ एक अंतर्निहित पैरामीटर सूची परिभाषित के साथ एक foo के लिए काम नहीं करता।

4

मेरे सर्वोत्तम ज्ञान के लिए, अंतर्निहित संकल्प उपयोग साइट पर होना चाहिए, और इसे दूर नहीं किया जा सकता है। निराशा का मेरा पल था जब मैं अपने कोड में 'निष्पादन कॉन्टेक्स्ट' प्रसार के आसपास काम करने की कोशिश कर रहा था।

एक समझौता मैं पर विचार किया गया है था:

type Async[A] = ExecutionContext => Future[A] 

def countFiles(root: String): Async[Int] = implicit ec => 
    // ... 

'implicit' केवल समारोह के भीतर रखती है - हम मंगलाचरण पर समझौता करने के लिए है:

implicit class AsyncExt[A](async: Async[A]) { 
    def invoke()(implicit ec: ExecutionContext) = async(ec) 
} 

implicit val ec = ... 
countFiles("/").invoke() 

एक और समझौता - मैंने चुना और अफसोस के लिए जीता:

class AsyncFileCounter(ec: ExecutionContext) { 
    def countFiles(root: String): Future[A] = ... 
} 

class FileCounter { 
    def async(implicit ec: ExecutionContext) = new AsyncFileCounter(ec) 
} 

यह निष्पक्षता से उपयोग को बदलता है (लेकिन डी जन्म दिया):

implicit val ec = ... 
val counter = new FileCounter 
counter.countFiles("/") // <-- nope 
निम्नलिखित करने के लिए

:

implicit val ec = ... 
val counter = new FileCounter 
counter.async.countFiles("/") // yep! 

अपने संदर्भ के आधार पर यह सहने हो सकता है। आप 'डीईएफ लेनदेन' जोड़ सकते हैं जहां मैंने'def async 'का उपयोग किया था।

मुझे इस पर अफसोस है, क्योंकि यह विरासत को जटिल बनाता है, और कुछ आवंटन ओवरहेड (हालांकि इसे दूर किया जाना चाहिए)।

नीचे की रेखा यह है कि आपको अपने कार्य को आमंत्रित करने के लिए एक अधिक स्पष्ट टुकड़े टुकड़े विधि के साथ आना होगा - जो कि अकेले करी से कम सुरुचिपूर्ण है।

+2

आपके दूसरे मामले (यानी फाइलकॉन्टर) के बारे में, क्या आप एक अंतर्निहित रूपांतरण 'अंतर्निहित डीफ काउंटरटोएसिंक (सी: फाइलकॉन्टर): AsyncFileCounter = c.async' परिभाषित नहीं कर सकते हैं ताकि आप एक बार फिर counter.countFiles ("/") ' –

+0

अच्छा! मेरे मामले में अंतर्निहित रूपांतरण समेकित विधियों द्वारा समान ऑब्जेक्ट पर मौजूद समान हस्ताक्षर के साथ पराजित किया जाएगा। हालांकि, यह निश्चित रूप से एक अच्छा बॉयलरप्लेट कामकाज है! मुझे वास्तव में यह सत्यापित करने की आवश्यकता है कि बचने का विश्लेषण वास्तव में Async ऑब्जेक्ट के लिए ढेर आवंटन को समाप्त करता है। – nadavwr

+0

मैं कहूंगा कि सिंक्रोनस विधियों के पास एक अलग हस्ताक्षर होगा, क्योंकि वे 'भविष्य [ए]' नहीं बल्कि एक 'ए' वापस नहीं करेंगे, इसलिए संकलक आपको बता सकता है।आपको बस उन क्षेत्रों को सीमित करना चाहिए जहां आपको एसिंक कॉल की आवश्यकता है और वहां पर लागू रूपांतरण आयात करें। ढेर आवंटन से बचने के लिए मैं उस पर शर्त नहीं लगा सकता ... –

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