2013-07-08 4 views
12

कैसे कर सकते हैं मैं (सर्वोत्तम) एक विकल्प आज़माएं में एक विधि कॉल द्वारा दिया (वरीयता द्वारा, हालांकि एक या तो या एक scalaz \/ या यहां तक ​​कि एक मान्यता ठीक हो सकता है) अगर उचित एक विफलता मूल्य निर्दिष्ट करने सहित कन्वर्ट?मैं कैसे (सर्वोत्तम) में एक प्रयास करें एक विकल्प बदल सकता हूँ?

उदाहरण के लिए, मैं निम्नलिखित कोड है, जो kludgy महसूस करता है, लेकिन कम से कम (के सबसे) क्या करता है काम किया है:

import scala.util._ 

case class ARef(value: String) 
case class BRef(value: String) 
case class A(ref: ARef, bRef: BRef) 
class MismatchException(msg: String) extends RuntimeException(msg) 

trait MyTry { 

    // Given: 
    val validBRefs: List[BRef] 

    // Want to go from an Option[A] (obtained, eg., via a function call passing a provided ARef) 
    // to a Try[BRef], where the b-ref needs to be checked against the above list of BRefs or fail: 

    def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = { 

    val abRef = for { 
     a <- get[A](aRef) // Some function that returns an Option[A] 
     abRef = a.bRef 
     _ <- validBRefs.find(_ == abRef) 
    } yield (abRef) 

    abRef match { 
     case Some(bRef) => Success(bRef) 
     case None => Failure(new MismatchException("No B found matching A's B-ref")) 
    } 
    } 
} 

यह लगता है जैसे वहाँ के लिए अंतिम मैच होने के लिए एक तरह से किया जाना चाहिए एक नक्शा या flatMap या इसी तरह के निर्माण में बदल गया और समझ के लिए पूर्ववर्ती में शामिल किया।

इसके अलावा, अगर मैं एआरएफ से एक विकल्प [ए] विफल करने के लिए कॉल विफल रहता हूं (बीआरएफ चेक विफल होने की तुलना में कोई नहीं लौटा) तो मुझे एक अलग विफलता संदेश निर्दिष्ट करने में सक्षम होना पसंद करेंगे (मुझे केवल एक कारण जानने की परवाह है विफलता के लिए, इसलिए एक scalaz प्रमाणीकरण आदर्श फिट की तरह महसूस नहीं करता है)।

यह एक इकाई ट्रांसफार्मर का उपयोग करने के लिए एक उपयुक्त जगह है? यदि हां, तो scalaz एक उपयुक्त एक प्रदान करता है, या किसी को यह कैसा लगेगा का एक उदाहरण दे सकते हैं?

+0

क्या आपका मतलब है 'कोशिश करें {abRef.getOrElse (नया मिस्चैच अपवाद ("कोई बी मिलान मिलान ए के बी-रेफ"))} या 'abRef.map {सफलता (_)} .getOrElse (विफलता (नया मिस्चैच अपवाद ("नो बी मिलान ए के बी-रेफ मिला")) '? – senia

+0

@senia अधिक बाद वाले: 'abRef.map {सफलता (_)} .getOrElse (विफलता (नया मिस्चैच अपवाद (" कोई बी मिलान ए के बी-रेफ मिला)) ', लेकिन ऐसा लगता है जैसे यह संभव होना चाहिए - और अधिक मूर्खतापूर्ण - इसे किसी भी तरह समझने के लिए। – Shadowlands

+0

एक साइड नोट के रूप में, 'विकल्प' पर 'फ़िल्टर' का उपयोग क्यों न करें- यानी,' प्राप्त करें [ए] (एआरएफ)। मैप (_। बीआरएफ) .filter (validBRefs.contains) 'के साथ अपनी' समझ 'के लिए प्रतिस्थापित करें। ? –

उत्तर

5

यदि आप एक Try से के साथ शुरू की कोशिश की [विभिन्न विफलताओं की पहचान के लिए संपादित] अपने लिए कंप्यूटर अनुप्रयोग तो आप समाप्त कर सकते हैं के साथ जाना हो जाओ अंत में मैच। आप को पर fold के माध्यम से Option पर मजबूर कर सकते हैं। यहां यह देखा जा सकता है कि:

def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = { 
    for { 
    a <- get[A](aRef).fold[Try[A]](Failure[A](new OtherException("Invalid aRef supplied")))(Success(_)) 
    abRef = a.bRef 
    _ <- validBRefs.find(_ == abRef).fold[Try[BRef]](Failure(new MismatchException("No B found matching A's B-ref")))(Success(_)) 
    } yield abRef 
} 

इस दृष्टिकोण के साथ, आप दो अलग-अलग चेक के लिए अलग-अलग अपवाद प्राप्त कर सकते हैं। यह सही नहीं है, लेकिन शायद यह आपके लिए काम करेगा।

+0

आह, यही वही है जो मैं उम्मीद कर रहा था - मोल्ड विधि को याद किया (हालांकि ऐसा लगता है कि केवल स्कैला 2.10.x के साथ आया था)। चीयर्स @ कंबैक्सटर! – Shadowlands

-1

मैं कोई वैकल्पिक समाधान बाहर काम किया है, हालांकि यह अभी भी मेरे मामले कि विकल्प [एक] बनाम BREF मान्य नहीं किया जा रहा है कोई नहीं है के लिए एक अलग विफलता संदेश निर्दिष्ट करने के लिए अनुमति नहीं देता:

def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = 
    Try { 
    (for { 
     a <- get[A](aRef) 
     bRef = a.bRef 
     _ <- bs.find(_ == bRef) 
    } yield (bRef)) getOrElse (throw new MismatchException("No B found matching A's B-ref")) 
    } 

मुझे लगता है कि मुझे उम्मीद है कि लौटाए गए विकल्प [ए] को एक कोशिश में जल्दी से परिवर्तित करने का तरीका होना चाहिए (एक उपयुक्त रूप से बेवकूफ स्कैला मार्ग - उदाहरण के लिए। समझ के अंदर), फिर प्रसंस्करण जारी रखें (प्राप्त करना और रास्ते में किसी भी उपयुक्त विफलताओं को निर्धारित करते समय बी-रेफरी की जांच करना)। जहां जरूरत उचित अपवाद फेंकने और पूरे लपेटकर द्वारा

def getValidBRefForReferencedA(aRef: ARef): Either[Throwable,BRef] = {  
    for { 
    a <- get[A](aRef).toRight[Throwable](new Exception("Invalid ARef")).right 
    bRef <- validBRefs.find(_ == a.bRef).toRight(new MismatchException("No B found matching A's B-ref")).right 
    } yield bRef 
} 

, तो आप बस, एक बहुत ही प्रक्रियात्मक तरीके से अपने कोड लिख सकते हैं एक Try का उपयोग करना:

2

आप एक Either का उपयोग करना चाहते हैं, तो आप उपयोग कर सकते हैं Option.toRight Try.apply (जो अपवाद को पकड़ने और उन्हें Failure उदाहरणों के रूप में पेश करेंगे) के साथ।

def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = Try { 
    val a = get[A](aRef).getOrElse(throw new Exception("Invalid ARef")) 
    validBRefs.find(_ == a.bRef).getOrElse(throw new MismatchException("No B found matching A's B-ref")) 
} 
1

आसान बनाने के लिए

def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = { 
    val abRef = for { 
    a <- get[A](aRef) 
    bRef = a.bRef 
    result = Either.cond(validBRefs.contains(bRef), bRef, "Invalid B Reference") 
    } yield result 

    abRef.map { 
    case Right(bRef) => Success(bRef) 
    case Left(error) => Failure(new InvalidReferenceException(error)) 
    }.getOrElse(Failure(new MismatchException("No B found matching A's B-ref"))) 
} 
3

आप एक अंतर्निहित रूपांतरण

implicit class OptionOps[A](opt: Option[A]) { 

    def toTry(msg: String): Try[A] = { 
     opt 
     .map(Success(_)) 
     .getOrElse(Failure(new NoSuchElementException(msg))) 
    } 
    } 

स्काला मानक lib दृष्टिकोण के इस प्रकार का उपयोग करता है का उपयोग कर सकते हैं।देखें http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html#companion-objects-of-a-type

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