2017-02-10 6 views
14

में अच्छी तरह से गठबंधन करने के लिए कैसे करें मेरे सभी एपीआई विधियों ने भविष्य [विकल्प [टी]] लौटाया है, यह समझने की कोशिश कर रहा है कि निम्नलिखित तरीके से कैसे निष्पादित किया जाए :मेरा एपीआई भविष्य में वापस आ रहा है [विकल्प [टी]], उन्हें

case class UserProfile(user: User, location: Location, addresses: Address) 

नीचे कोड वर्तमान में संकलित करता है नहीं उपयोगकर्ता, स्थान, और पता कर रहे हैं, क्योंकि सभी विकल्प [उपयोगकर्ता], विकल्प [स्थान] और विकल्प [पता]

val up = for { 
user <- userService.getById(userId) 
location <- locationService.getById(locationId) 
address <- addressService.getById(addressId) 
} yield UserProfile(user, location, address) 

मुझे लगता है कि scalaz याद ऑप्शन टी है लेकिन मैंने पहले कभी इसका इस्तेमाल नहीं किया है और यह सुनिश्चित नहीं किया कि इसे मेरी स्थिति में कैसे लागू किया जाए।

यदि उपयोगकर्ता, स्थान या पता वास्तव में वापस आते हैं, तो विकल्प विकल्प का उपयोग करते समय क्या होगा जब मुझे इस मामले में 3 मॉडल पर लागू करने की आवश्यकता होगी?

+0

चूंकि यह स्पष्ट रूप से 'विकल्प टी' के बारे में है, हो सकता है कि इसमें 'स्केलज़' टैग (और संभवतः 'मोनैड-ट्रांसफॉर्मर्स' और/या 'स्कैला-बिल्लियों' भी हो)? –

उत्तर

21

एक पूरा काम कर उदाहरण के लिए कुछ सरल परिभाषाएँ:

import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.Future 

type User = String 
type Location = String 
type Address = String 

case class UserProfile(user: User, location: Location, addresses: Address) 

def getUserById(id: Long): Future[Option[User]] = id match { 
    case 1 => Future.successful(Some("Foo McBar")) 
    case _ => Future.successful(None) 
} 

def getLocationById(id: Long): Future[Option[Location]] = id match { 
    case 1 => Future.successful(Some("The Moon")) 
    case _ => Future.successful(None) 
} 

def getAddressById(id: Long): Future[Option[Address]] = id match { 
    case 1 => Future.successful(Some("123 Moon St.")) 
    case _ => Future.successful(None) 
} 

और पूर्णता के लिए के लिए, यहाँ क्या Scalaz मुक्त कार्यान्वयन इस तरह दिखाई देगा:

def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] = 
    for { 
    maybeUser  <- getUserById(uid) 
    maybeLocation <- getLocationById(lid) 
    maybeAddress <- getAddressById(aid) 
    } yield (
    for { 
     user  <- maybeUser 
     location <- maybeLocation 
     address <- maybeAddress 
    } yield UserProfile(user, location, address) 
) 

अर्थात हमें समझने के लिए घोंसला करना है, जैसे कि हमें map को घूमने के लिए घोंसला करना होगा उदा। Int मान जो Future[Option[Int]] के अंदर हो सकता है।

OptionT स्कालाज़ या बिल्लियों में मोनैड ट्रांसफार्मर आपको इस घोंसले के बिना Future[Option[A]] जैसे प्रकारों के साथ काम करने की अनुमति देने के लिए डिज़ाइन किया गया है। उदाहरण के लिए आप इस लिख सकते हैं:

import scalaz.OptionT, scalaz.std.scalaFuture._ 

def getProfile(uid: Long, lid: Long, aid: Long): OptionT[Future, UserProfile] = 
    for { 
    user  <- OptionT(getUserById(uid)) 
    location <- OptionT(getLocationById(lid)) 
    address <- OptionT(getAddressById(aid)) 
    } yield UserProfile(user, location, address) 

या यदि आप एक Future[Option[UserProfile]] चाहता था तुम सिर्फ run कॉल कर सकते हैं:

def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] = (
    for { 
    user  <- OptionT(getUserById(uid)) 
    location <- OptionT(getLocationById(lid)) 
    address <- OptionT(getAddressById(aid)) 
    } yield UserProfile(user, location, address) 
).run 

और फिर:

scala> getProfile(1L, 1L, 1L).foreach(println) 
Some(UserProfile(Foo McBar,The Moon,123 Moon St.)) 

तो मध्यवर्ती परिणाम के किसी भी कर रहे हैं None, पूरी बात None होगी:

scala> getProfile(1L, 1L, 0L).foreach(println) 
None 

scala> getProfile(0L, 0L, 0L).foreach(println) 
None 

और निश्चित रूप से यदि कोई अनुरोध विफल हो जाता है, तो पूरी चीज पहली त्रुटि के साथ विफल हो जाती है।

एक फुटनोट के रूप में, यदि अनुरोध एक दूसरे पर निर्भर नहीं है, तो आप उन्हें applicatively बजाय monadically रचना कर सकते हैं:

import scalaz.Scalaz._ 

def getProfile(uid: Long, lid: Long, aid: Long): Future[Option[UserProfile]] = (
    OptionT(getUserById(uid)) |@| 
    OptionT(getLocationById(lid)) |@| 
    OptionT(getAddressById(aid)) 
)(UserProfile.apply _).run 

इस मॉडल गणना अधिक सही और के बाद से चला सकते हैं और अधिक कुशल हो सकता है समानांतर में अनुरोध।

+0

यही वह है जिसे मैं घर चलाने वाला आदमी कहता हूं, धन्यवाद! | @ | भविष्य की तरह है। परिणाम? – Blankman

+0

@ ब्लैंकमैन हाँ- बड़ा अंतर यह है कि यह विभिन्न प्रकारों (प्रकारों और धर्मार्थियों को बनाए रखने) के साथ काम करता है। –

+1

एफवाईआई: 'Future.onSuccess' को स्केल 2.12 https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-5 के बाद से बहिष्कृत किया गया है।md – n4to4

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