#scala
#scala #сопоставление с образцом #case-class
Вопрос:
Что происходит в девятой строке ниже, что делает result
переменную доступной в десятой строке?
Пример взят из документации Akka по тестированию. Ask
В восьмой строке возвращается a scala.concurrent.Future
. Future.value()
Возвращает параметр[Try[T]] , который будет либо Some(Success(t))
или Some(Failure(error))
. Some.get
Вызывается Then, который должен либо возвращать t
, либо ошибку, в зависимости от результата Try
.
Похоже, что независимо от того, является ли значение future.value.get
ошибкой в девятой строке или нет, он пытается создать экземпляр нового Success , который определяется как класс case в Try , с возвращаемым значением from Some.get
. Успех в девятой строке не используется напрямую, но вместо этого параметр конструктора класса case result
каким-то образом помещает его в область видимости, чтобы его можно было использовать в десятой строке. Как это называется в Scala? Где я могу узнать больше о том, как работает этот синтаксис?
1. import akka.testkit.TestActorRef
2. import scala.concurrent.duration._
3. import scala.concurrent.Await
4. import akka.pattern.ask
5.
6. val actorRef = TestActorRef(newMyActor)
7. // hypothetical message stimulating a '42' answer
8. val future = actorRef ? Say42
9. val Success( result: Int ) = future.value.get
10. result should be (42)
Ответ №1:
val Success( result: Int ) = future.value.get
соответствует шаблону. Вы можете использовать сопоставление с образцом для присвоения значений идентификаторам при объявлении значения val. Это примерно то же самое, что писать:
val result: Int = future.value.get match {
case Success(r: Int) => r
}
Обратите внимание, что это не исчерпывающее совпадение, и если future.value.get
это a Failure
, то MatchError
будет выбрано a . В контексте модульных тестов я постоянно использую сопоставление с образцом, подобное этому, поскольку a MatchError
было бы еще одним признаком сбоя.
Вот несколько примеров аналогичных (более безопасных) назначений сопоставления с образцом:
val (a, b) = (1, 2)
case class Test(i: Int, j: String)
val test = Test(1, "a")
val (i, j) = test
val list = List(1, 2, 3, 4)
val List(first, second, _*) = list // though this will fail if the List has less than 3 elements
Ответ №2:
Это просто сопоставление с образцом. Например:
scala> val Some(a) = Some(5)
a: Int = 5
scala> val Some(a) = None: Option[Int]
scala.MatchError: None (of class scala.None$)
... 33 elided
эквивалентно:
scala> val a = Some(5) match {case Some(a) => a}
a: Int = 5
scala> val a = (None: Option[Int]) match {case Some(a) => a}
scala.MatchError: None (of class scala.None$)
... 33 elided
в обоих случаях Some.unapply
вызывается метод (который является частью сопутствующего объекта, автоматически генерируемого для класса case).
В общем, для выражения, подобного val Extractor(a, Extractor(b, c)) = input
scala-compiler, внутренне генерирует (вы можете проверить это с помощью макросов) специальные синтетические выражения:
val tuple = input match { //synthetic value here
Extractor(a, Extractor(b, c)) => (a,b,c)
}
val a = tuple._1
val b = tuple._2
val c = tuple._3
Ответ №3:
Это называется сопоставлением с образцом.