Как это называется, когда параметр конструктора класса case используется вне класса?

#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: