Scala Language
선물
수색…
미래 창조
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
object FutureDivider {
def divide(a: Int, b: Int): Future[Int] = Future {
// Note that this is integer division.
a / b
}
}
아주 간단하게 divide
방법의 몫으로 해결하는 미래를 만들어 오버 a
b
.
성공적인 미래를위한 소비
성공적인 미래를 소비하는 가장 쉬운 방법은 미래의 가치를 얻는 것입니다. map
방법을 사용하는 것입니다. 일부 코드가 "미래 만들기"예제에서 FutureDivider
객체의 divide
메서드를 호출한다고 가정합니다. 코드의 몫 얻는처럼 무엇을해야 오버 a
b
?
object Calculator {
def calculateAndReport(a: Int, b: Int) = {
val eventualQuotient = FutureDivider divide(a, b)
eventualQuotient map {
quotient => println(quotient)
}
}
}
실패한 미래 소비
Future의 계산이 예외를 생성하여 Future가 실패하게 만드는 경우가 있습니다. "Creating a Future"예제에서 호출 코드가 divide
메소드에 55
와 0
을 전달하면 어떻게 될까요? 물론 0으로 나눈 후에 ArithmeticException
을 던질 것입니다. 소비 코드에서 어떻게 처리 될까요? 실제로 실패를 처리 할 수있는 몇 가지 방법이 있습니다.
recover
및 패턴 일치로 예외를 처리하십시오.
object Calculator {
def calculateAndReport(a: Int, b: Int) = {
val eventualQuotient = FutureDivider divide(a, b)
eventualQuotient recover {
case ex: ArithmeticException => println(s"It failed with: ${ex.getMessage}")
}
}
}
예외가 failed
프로젝션으로 예외를 처리합니다. 여기서 예외는 미래의 값이됩니다.
object Calculator {
def calculateAndReport(a: Int, b: Int) = {
val eventualQuotient = FutureDivider divide(a, b)
// Note the use of the dot operator to get the failed projection and map it.
eventualQuotient.failed.map {
ex => println(s"It failed with: ${ex.getMessage}")
}
}
}
미래를 함께 가다.
이전 예제는 성공과 실패 사례를 처리하면서 미래의 개별 기능을 시연했습니다. 그러나 일반적으로 두 기능은 훨씬 더 간결하게 처리됩니다. 다음은 깔끔하고 사실적인 방식으로 작성된 예제입니다.
object Calculator {
def calculateAndReport(a: Int, b: Int) = {
val eventualQuotient = FutureDivider divide(a, b)
eventualQuotient map {
quotient => println(s"Quotient: $quotient")
} recover {
case ex: ArithmeticException => println(s"It failed with: ${ex.getMessage}")
}
}
}
순차 및 순회 선물
어떤 경우에는 별도의 선물에서 다양한 금액의 가치를 계산해야합니다. List[Future[Int]]
가 있다고 가정하고 대신 List[Int]
를 처리해야합니다. 그런 다음 질문은 List[Future[Int]]
의이 인스턴스를 Future[List[Int]]
입니다. 이를 위해 Future
동반자 객체에 sequence
메소드가 있습니다.
def listOfFuture: List[Future[Int]] = List(1,2,3).map(Future(_))
def futureOfList: Future[List[Int]] = Future.sequence(listOfFuture)
일반적으로 sequence
는 F
와 G
대한 제한을 가지고 F[G[T]]
를 G[F[T]]
로 변환하는 함수 프로그래밍 세계에서 일반적으로 알려진 연산자입니다.
traverse
라고하는 대체 연산자가 있지만 비슷한 기능을하지만 추가 인수로 함수를 사용합니다. 신원 함수 x => x
를 매개 변수로 사용하면 sequence
연산자처럼 작동합니다.
def listOfFuture: List[Future[Int]] = List(1,2,3).map(Future(_))
def futureOfList: Future[List[Int]] = Future.traverse(listOfFuture)(x => x)
다만, 추가의 인수에 의해, 지정된 listOfFuture
내의 장래의 각 인스턴스를 변경할 수 있습니다. 또한, 첫 번째 인수는 Future
의 목록 일 필요는 없습니다. 따라서 다음과 같이 예제를 변형 할 수 있습니다.
def futureOfList: Future[List[Int]] = Future.traverse(List(1,2,3))(Future(_))
이 경우 List(1,2,3)
는 첫 번째 인수로 직접 전달되고 identity 함수 x => x
는 Future(_)
로 대체되어 유사하게 각 Int
값을 Future
로 래핑합니다. 이것의 이점은 성능 향상을 위해 중간 List[Future[Int]]
을 생략 할 수 있다는 것입니다.
여러 선물 결합 - 이해를 돕기 위해
for comprehension 은 여러 미래의 성공적인 결과에 의존하는 코드 블록을 실행하는 간결한 방법입니다.
f1, f2, f3
3 개의 Future[String]
각각 one, two, three
의 문자열이 포함됩니다.
val fCombined =
for {
s1 <- f1
s2 <- f2
s3 <- f3
} yield (s"$s1 - $s2 - $s3")
fCombined
는 모든 미래가 성공적으로 완료되면 문자열 one - two - three
포함하는 Future[String]
가됩니다.
여기에는 암시 적 ExectContext가 사용됩니다.
또한 이해는 flatMap 메소드에 대한 구문 론적 설탕 일 뿐이므로 신체 내부의 미래 객체 구성은 미래로 둘러싸인 코드 블록의 동시 실행을 제거하고 순차 코드로 이어지게된다는 것을 명심하십시오. 예를 들어 보자.
val result1 = for {
first <- Future {
Thread.sleep(2000)
System.currentTimeMillis()
}
second <- Future {
Thread.sleep(1000)
System.currentTimeMillis()
}
} yield first - second
val fut1 = Future {
Thread.sleep(2000)
System.currentTimeMillis()
}
val fut2 = Future {
Thread.sleep(1000)
System.currentTimeMillis()
}
val result2 = for {
first <- fut1
second <- fut2
} yield first - second
result1
객체로 묶인 값은 항상 음수이고 result2
는 양수입니다.
일반적으로 이해 및 yield
에 대한 자세한 내용은 http://docs.scala-lang.org/tutorials/FAQ/yield.html을 참조 하십시오.