[SCALA] 스칼라의 미래 [옵션]를위한 지능형
SCALA스칼라의 미래 [옵션]를위한 지능형
나는 선물을 돌려 두 가지 기능을 가지고있다. 나는에 대한 수율 이해를 사용하여 다른에 첫 번째 함수에서 수정 된 결과를 공급하기 위해 노력하고있어.
이 방법은 작동합니다 :
val schoolFuture = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- schoolStore.getSchool(sid.get) if sid.isDefined
} yield s
그러나 내가 가진 행복하지 해요 거기에, 내가 대신지도를 사용할 수 있어야 것으로 보인다 "만일".
그러나 나는지도 할 때 :
val schoolFuture: Future[Option[School]] = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- sid.map(schoolStore.getSchool(_))
} yield s
나는 컴파일 오류가 발생합니다 :
[error] found : Option[scala.concurrent.Future[Option[School]]]
[error] required: scala.concurrent.Future[Option[School]]
[error] s <- sid.map(schoolStore.getSchool(_))
나는 몇 가지 변화와 주변 연주했지만, 작품이 매력적인 아무것도 발견하지 않았습니다. 사람이 더 좋은 이해를 제안 및 / 또는 제 2 예 뭐가 잘못 됐는지 설명 할 수 있습니까?
다음은 스칼라 2.10로 최소하지만 완전한 실행 가능한 예제입니다 :
import concurrent.{Future, Promise}
case class User(userId: Int)
case class UserDetails(userId: Int, schoolId: Option[Int])
case class School(schoolId: Int, name: String)
trait Error
class UserStore {
def getUserDetails(userId: Int): Future[Either[Error, UserDetails]] = Promise.successful(Right(UserDetails(1, Some(1)))).future
}
class SchoolStore {
def getSchool(schoolId: Int): Future[Option[School]] = Promise.successful(Option(School(1, "Big School"))).future
}
object Demo {
import concurrent.ExecutionContext.Implicits.global
val userStore = new UserStore
val schoolStore = new SchoolStore
val user = User(1)
val schoolFuture: Future[Option[School]] = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- sid.map(schoolStore.getSchool(_))
} yield s
}
해결법
-
==============================
1.약속 [옵션 [A] 힘의 도움에 대한 비슷한 질문이 대답. 그냥 약속을 위해 미래를 대체합니다.
약속 [옵션 [A] 힘의 도움에 대한 비슷한 질문이 대답. 그냥 약속을 위해 미래를 대체합니다.
나는 당신의 질문에서 getUserDetails 및 getSchool에 대한 다음과 같은 유형을 추론하고 있습니다 :
getUserDetails: UserID => Future[Either[??, UserDetails]] getSchool: SchoolID => Future[Option[School]]
대신 옵션으로 바뀌는 상기 어느 하나로부터 오류 값을 무시하므로, 효율적으로 A 형의 두 값이 => 미래 [옵션 [B].
당신은 미래를위한 모나드 인스턴스를했으면 (scalaz에 하나있을 수 있습니다, 또는 당신은 내가 링크 된 대답으로 자신을 쓸 수 있습니다) 다음과 같이 보일 것이다 문제에 대한 OptionT 변압기를 적용 :
for { ud <- optionT(getUserDetails(user.userID) map (_.right.toOption)) sid <- optionT(Future.successful(ud.schoolID)) s <- optionT(getSchool(sid)) } yield s
호환되는 형식을 유지하기 위해 다음 사항을 참고 ud.schoolID는 (이미 완료) 미래에 싸여있다.
이것에 대한-이해의 결과는 타입 OptionT [미래, SchoolID]을 것이다. 당신은 유형 미래 [옵션 [SchoolID]]의 값을 갖는 변압기의 실행 방법을 추출 할 수 있습니다.
-
==============================
2.(편집은 정확한 답을 줄 수 있습니다!)
(편집은 정확한 답을 줄 수 있습니다!)
열쇠는 여기에 미래와 옵션 올바른 flatMap 서명이 없기 때문에 아니 작성 내부를 할 것입니다. 말씀 드리지만, desugars에 대한 같은 :
for ( x0 <- c0; w1 = d1; x1 <- c1 if p1; ... ; xN <- cN) yield f c0.flatMap{ x0 => val w1 = d1 c1.filter(x1 => p1).flatMap{ x1 => ... cN.map(xN => f) ... } }
(있는 경우 문을 체인으로 필터를 던졌습니다 곳 -과는 체인의 다음 부분 전에 변수를 설정 문을 동일 - I've은 단지 하나의 예를 제공). 당신은 단지 flatMap 다른 선물, 모든 문 C0, C1은 ... 마지막을 제외하고 더 나은 미래를 생산했다 수 있기 때문에.
- 이제 getUserDetails 및 getSchool 모두 생산 선물,하지만 시드 그래서 우리는의 <오른쪽에 넣을 수없는 옵션입니다. 불행하게도,이 작업을 수행 할 깨끗한 아웃 - 오브 - 박스 방법이 없다. O가 옵션 인 경우, 우리는 할 수
o.map(Future.successful).getOrElse(Future.failed(new Exception))
이미 완성 된 미래에 옵션을 켭니다. 그래서
for { ud <- userStore.getUserDetails(user.userId) // RHS is a Future[Either[...]] sid = ud.right.toOption.flatMap(_.schoolId) // RHS is an Option[Int] fid <- sid.map(Future.successful).getOrElse(Future.failed(new Exception)) // RHS is Future[Int] s <- schoolStore.getSchool(fid) } yield s
트릭을 할 것입니다. 그게 당신이있어보다 더 나은가요? 못 미더운. 하지만 경우
implicit class OptionIsFuture[A](val option: Option[A]) extends AnyVal { def future = option.map(Future.successful).getOrElse(Future.failed(new Exception)) }
다음 갑자기을 위해-이해 합리적인 다시 보이는 :
for { ud <- userStore.getUserDetails(user.userId) sid <- ud.right.toOption.flatMap(_.schoolId).future s <- schoolStore.getSchool(sid) } yield s
이것은이 코드를 작성하는 가장 좋은 방법이 있나요? 아마 아닙니다; 그것은 당신이 그 시점에서 다른 무엇을해야할지 몰라 간단하기 때문에 예외에 없음을 변환하지 않습니다에 의존한다. 이 때문에 미래의 디자인 결정의 주위에 일하기 어렵다; 나는 (필터를 호출) 원래 코드가 할 수있는 방법의 좋은으로 적어도 것을 건의 할 것입니다.
-
==============================
3.어떤 행동을하면이 옵션 [학교] 아무도 없다는 경우에 발생하는 하시겠습니까? 미래처럼 당신은 실패 할 것인가? 예외의 종류와? 좋아 당신은 결코 완료하는 데겠습니까? (나쁜 생각처럼 그 소리).
어떤 행동을하면이 옵션 [학교] 아무도 없다는 경우에 발생하는 하시겠습니까? 미래처럼 당신은 실패 할 것인가? 예외의 종류와? 좋아 당신은 결코 완료하는 데겠습니까? (나쁜 생각처럼 그 소리).
여하튼, 필터 메소드 호출에 대한 표현 desugars의 경우 절. 미래에 # 계약은 따라서 filteris :
하지만 기다려:
scala> None.get java.util.NoSuchElementException: None.get
당신이 볼 수 있듯이, None.get 똑같은 일을 반환합니다.
따라서, sid.isDefined 일을해야하는 경우 치우는, 이것은 합리적인 결과를 반환해야합니다 :
val schoolFuture = for { ud <- userStore.getUserDetails(user.userId) sid = ud.right.toOption.flatMap(_.schoolId) s <- schoolStore.getSchool(sid.get) } yield s
schoolFuture의 결과가 scala.util.Failure [예외 : NoSuchElementException]의 인스턴스가 될 수 있음을 유의하십시오. 그러나 당신은 당신이 원하는 어떤 다른 행동을 설명하지 않았다.
-
==============================
4.우리는 하나의 모나드와 같은 역할을하지 미래 [옵션 [T]]에 작은 래퍼를했습니다 (모나드 법률의 아무도도 확인 아무도하지만,지도, flatMap, foreach는, 필터 등이있다) - MaybeLater. 그것은 비동기 옵션보다 훨씬 더 작동합니다.
우리는 하나의 모나드와 같은 역할을하지 미래 [옵션 [T]]에 작은 래퍼를했습니다 (모나드 법률의 아무도도 확인 아무도하지만,지도, flatMap, foreach는, 필터 등이있다) - MaybeLater. 그것은 비동기 옵션보다 훨씬 더 작동합니다.
이 냄새 나는 코드를 많이 있습니다,하지만 어쩌면 그것은 예를 들어 적어도 도움이 될 것입니다. 의 : 열려 많은 질문이 있습니다 (여기 예에 대한이.)
-
==============================
5.그것은 A-일반 형식 변환 할 https://github.com/qifun/stateless-future 또는 https://github.com/scala/async을 사용하기 쉽습니다.
그것은 A-일반 형식 변환 할 https://github.com/qifun/stateless-future 또는 https://github.com/scala/async을 사용하기 쉽습니다.
from https://stackoverflow.com/questions/14385633/futureoption-in-scala-for-comprehensions by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] IDEA에서 SBT 소스 (0) | 2019.11.26 |
---|---|
[SCALA] 어떻게 플레이 프레임 워크를 사용하여 SSL을 통해 원격 MySQL 데이터베이스에 연결하는? (0) | 2019.11.26 |
[SCALA] 스칼라의 심볼을 사용하는 실제 예? (0) | 2019.11.26 |
[SCALA] 기능적 프로그래밍 - 재귀에 대한 강조, 왜 많은? (0) | 2019.11.26 |
[SCALA] 쉬운 방법은 SBT에 의해 생성 * 모든 * 없애? (0) | 2019.11.26 |