2013-07-28 11 views
21

क्या scala.util चेन करना संभव है। कोशिश करें और scala.concurrent.Future? वे दोनों प्रभावी ढंग से एक ही मोनैडिक इंटरफेस प्रदान करते हैं, लेकिन उन्हें चेन करने का प्रयास संकलन त्रुटि में परिणाम देता है।स्कैला - चेनिंग वायदा ब्लॉक का प्रयास करें?

उदाहरण के लिए। नीचे

def someFuture:Future[String] = ??? 
def processResult(value:String):Try[String] = ??? 

दो हस्ताक्षरों को देखते हुए यह है संभव निम्नलिखित की तरह कुछ करने के लिए?

val result = for(a <- someFuture; b <- processResult(a)) yield b; 
result.map { /* Success Block */ } recover { /* Failure Block */ } 

यह स्पष्ट रूप से एक संकलन त्रुटि में परिणाम देता है, क्योंकि भविष्य और प्रयास फ्लैट होने में असमर्थ हैं।

हालांकि यह श्रृंखला बनाने में सक्षम होने के लिए यह एक अच्छी सुविधा होगी - क्या यह संभव है? या क्या मुझे उन्हें भविष्य में संयोजित करने की ज़रूरत है [कोशिश करें [स्ट्रिंग]]?

(विशेष रूप से, मुझे भविष्य में या प्रयास में अपवादों को पकड़ने के लिए एकल 'पुनर्प्राप्ति' ब्लॉक रखने में दिलचस्पी है)।

उत्तर

27

जब इस तरह की समस्या का सामना करना पड़ता है, जहां आप समझ के लिए अलग-अलग प्रकार का उपयोग करना चाहते हैं, तो एक समाधान प्रकारों में से किसी एक को चुनने और चुनने और दूसरे प्रकार को मानचित्र करने के लिए किया जा सकता है। आपकी स्थिति के लिए, वायदा के अद्वितीय गुण (एसिंक) दिए गए, मैं सबसे कम आम denominator के रूप में Future का चयन करेंगे और Try को Future पर मानचित्रित करें। आप बस है कि इस तरह कर सकते हैं:

val result = for{ 
    a <- someFuture 
    b <- tryToFuture(processResult(a)) 
} yield b 
result.map { /* Success Block */ } recover { /* Failure Block */ } 

def tryToFuture[T](t:Try[T]):Future[T] = { 
    t match{ 
    case Success(s) => Future.successful(s) 
    case Failure(ex) => Future.failed(ex) 
    } 
} 

अब जबकि आपने यह एक बहुत ही सामान्य स्थिति होने के लिए और आप लगातार स्पष्ट रूपांतरण में जोड़ने के लिए होने पसंद नहीं आया, तो, मैं तुम्हें निहित के रूप में tryToFuture विधि निर्धारित कर सकते हैं लगता है कुछ सहायक ऑब्जेक्ट पर और इसे आयात जहां इस तरह की जरूरत:

object FutureHelpers{ 
    implicit def tryToFuture[T](t:Try[T]):Future[T] = { 
    t match{ 
     case Success(s) => Future.successful(s) 
     case Failure(ex) => Future.failed(ex) 
    } 
    } 
} 

import FutureHelpers._ 
val result = for{ 
    a <- someFuture 
    b <- processResult(a) 
} yield b 
result.map { /* Success Block */ } recover { /* Failure Block */ } 

बस याद रखें कि बुला Future.success और Future.failed एक प्रभाव जो कुछ पर ExecutionContext में है कि यह हुड के नीचे यह करने के लिए किसी अन्य कार्य प्रस्तुत करेगा दायरे में है।

संपादित

के रूप में विक्टर एक Future करने के लिए एक Try परिवर्तित करने की प्रक्रिया, टिप्पणी में बताया और भी आसान है अगर तुम सिर्फ Future.fromTry तरह अद्यतन उदाहरण में नीचे से का उपयोग करें:

val result = for{ 
    a <- someFuture 
    b <- Future.fromTry(processResult(a)) 
} yield b 
result.map { /* Success Block */ } recover { /* Failure Block */ } 

यह शायद आपकी सबसे अच्छी शर्त है जो प्रत्यारोपण के साथ सामान कर रही है या अपना स्वयं का रूपांतरण तर्क रोलिंग कर रही है।

+4

वर्तमान में है एक [चर्चा स्कैला-उपयोगकर्ता पर] (https://groups.google.com/d/topic/scala-user/Mu4_lZAWxz0/चर्चा) 'प्रयास' को 'भविष्य' में परिवर्तित करने की इस सटीक समस्या के बारे में। शायद इस तरह एक सहायक मानक मानक पुस्तकालय में कहीं भी शामिल किया जाना चाहिए। – gourlaysama

+0

भविष्य। फ्रॉम? –

+0

@ViktorKlang, हाँ आप सही हैं। मैंने उस दृष्टिकोण को शामिल करने के लिए अपना उत्तर अपडेट किया। सर उठाने के लिए धन्यवाद। – cmbaxter

2

के बारे में
val result = for(a <- someFuture) yield for(b <- processResult(a)) yield b; 

हालांकि यह साफ नहीं लगती है कैसे।

1
implicit def convFuture[T](ft: Future[Try[T]]): Future[T] = 
ft.flatMap { 
    _ match { 
    case Success(s) => Future.successful(s) 
    case Failure(f) => Future.failed(f) 
    } 
} 
2

शायद समस्या पुरानी है, लेकिन वर्तमान में आप कर सकते हैं:

implicit def tryToFuture[T](t:Try[T]):Future[T] = Promise.fromTry(t).future 
1

भी

Future.fromTry(Try { ... }) 

तो नहीं है तुम कर सकते हो

val result = for { 
    a <- someFuture 
    b <- Future.fromTry(processResult(a)) 
} yield b; 
संबंधित मुद्दे