switch/case изрази, но е
много по-гъвкав и мощенdef getDayOfWeek(day: Int): String = day match
case 1 => "Monday"
case 2 => "Tuesday"
case 3 => "Wednesday"
case 4 => "Thursday"
case 5 => "Friday"
case 6 => "Saturday"
case 7 => "Sunday"
case _ => "Invalid day!"<target> match
case <pattern1> => <result1>
case <pattern2> => <result2>
...
[case _ => <defaultResult>]
match и case_, който съвпада с
всичко и служи като default caseenum Color:
case Red, Green, Blue, Yellow, Orange, Purple
case class ShipmentId(value: String) extends AnyVal
case class User(name: String, age: Int)
def describe(x: Any): String = x match
case i: Int => s"An integer: $i"
case s: String => s"A string: $s"
case l: List[_] => s"A list of size ${l.size}"
case c: Color => s"A color: $c"
case s: ShipmentId => s"A shipment ID: ${s.value}"
case u: User => s"A user: ${u.name}, age ${u.age}"
case _: Double => "A random double"
case _ => "Unknown type"(pattern1, pattern2, ..., patternN)Person(pattern1, pattern2, pattern3)case class Person(name: String, age: Int, city: String)
val CanNowDrinkAlcohol = 18
def describePerson(p: Person): String = p match
case Person("Pesho", 24, "Varna") => "Pesho from Varna"
case Person(name, CanNowDrinkAlcohol, _) => s"$name can now drink alcohol"
case Person(name, _, city) => s"$name lives in $city"head :: tail - съставен образец за списък, който се
състои от глава и опашкаdef describeList[A](list: List[A]): String = list match
case Nil => "An empty list"
case head :: Nil => s"A single element list: $head"
case head :: tail => s"A list with head: $head and tail of size ${tail.size}"_?Seq(first, second, third)Seq(first, second, rest*)def describeSeq[A](seq: Seq[A]): String = seq match
case Seq() => "An empty sequence"
case Seq(first) => s"A single element sequence: $first"
case Seq(first, second) => s"A two element sequence: $first and $second"
case Seq(first, second, rest*) => s"A sequence with first: $first, " +
s"second: $second and rest of size ${rest.size}"sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(width: Double, height: Double) extends Shape
def describeShape(shape: Shape): String = shape match
case c @ Circle(r) => s"A circle $c with radius $r"
case r @ Rectangle(w, h) => s"A rectangle $r with width $w, height $h"@ ни позволява да даваме име на цялата
съвпаднала стойност, докато същевременно я декомпозираме с образецpattern1 | pattern2 | pattern3enum Color:
case Red, Green, Blue, Yellow, Orange, Purple
def isPrimaryColor(color: Color): Boolean = color match
case Color.Red | Color.Green | Color.Blue => true
case _ => false| ни позволява да съпоставяме няколко
алтернативни образeца в един casecase Some(x) | None => ...case Some(x) | Some(y) => ...case (x, y, z) | (x, y) => ...case a: String | b: Int => ...case Circle(r) | Rectangle(w, h) => ...pattern if conditiondef getDayOfWeek(day: Int): String = day match
case 1 => "Monday"
case 2 => "Tuesday"
case 3 => "Wednesday"
case 4 => "Thursday"
case 5 => "Friday"MatchError, ако подадем стойност, която не съвпада с нито
един от образцитеmatchFunction1, Function2,
PartialFunction и други функционални типовеmap, filter, flatMap,
collect, foldLeft, foldRight и
други функции от по-висок ред, които приемат функции като аргументиsealed trait Command
case class Move(x: Int, y: Int) extends Command
case object Stop extends Command
case class Speak(message: String) extends Command
def executeCommand: Command => Unit =
case Move(0, 0) => println("Staying in place")
case Move(x, y) => println(s"Moving to ($x, $y)")
case Stop => println("Stopping")
case Speak(message) => println(s"Speaking: $message")case class Person(name: String, age: Int, city: String)
val (first, second) = (1, "hello")
val person @ Person(name, age, city) = Person("Pesho", 24, "Varna")val list1 = List(1, 2, 3, 4, 5)
val list2 = List(10, 20, 30, 40, 50)
val list3 = List(100, 200)
for
(a, b) <- list1 zip list2
c <- list3
yield a + b + cval people = List(("Zdravko", 35), ("Boyan", 4), ("Viktor", 30), ("Taylor", 35))
for
case (name, 35) <- people
yield s"$name is 35"case пред образеца
withFilter или filter метод, който да може да
филтрира елементите спрямо образецаtry
doSomethingRisky()
catch
case e: NullPointerException => println("Caught a NullPointerException")
case e @ (_: UnsupportedOperationException | _: IllegalArgumentException) =>
println(s"Caught one of two special exceptions: ${e.getMessage}")
case e: Exception => println(s"Caught a general exception: ${e.getMessage}")
case NonFatal(e) => println(s"Caught a non-fatal exception: ${e.getMessage}")NonFatal е образец, който съвпада с всички изключения,
които не са фатални (като VirtualMachineError,
InterruptedException, OutOfMemoryError,
StackOverflowError и други)unapply или
unapplySequnapply методclass URL(protocol: String, domain: String)
object URL:
def unapply(url: String): Option[(String, String)] =
url.split("://", 2) match
case Array(protocol, rest) => Some((protocol, rest))
case _ => None
List(
"https://example.com",
"ftp://files.server.com",
"invalid-url",
"http://scala-lang.org"
)
.collect:
case URL(protocol, domain) => s"Protocol: $protocol, Domain: $domain"unapplySeq методclass CsvRow(values: String*)
object CsvRow:
def unapplySeq(row: String): Option[Seq[String]] =
Some(row.split(",").toSeq)
List("John,Doe,30", "Jane,Smith,25", "InvalidRow", "Alice,Bob")
.collect
case CsvRow(first, second, rest*) => s"First: $first, " +
s"Second: $second, Rest: ${rest.mkString(";")}"ADTs се изграждат чрез две основни концепции:
Case Class или Tuple)sealed Trait или
enum)Функциите имат експоненциална сложност
Математическа сложност: 23 = 8 възможни уникални имплементации.
sealed trait Notification
case class Email(address: String, subject: String, body: String) extends Notification
case class SMS(phoneNumber: String, message: String) extends Notification
case class Push(deviceToken: String, title: String, priority: Int) extends Notification // "Сума" от различни "Произведения"enum Result:
case Success(data: String)
case Failure
// You cannot easily use 'Success' as a type here
// because it is a value of the type 'Result'.
def process(success: Result.Success) = println(success.data)
// The compiler infers 'Result', losing the 'Success' specific info
val x = Result.Success("Done")
// will not compile
x.data
// We have to specifically define the type
val y: Result.Success = Result.Success("Done")
// compiles
y.datacase class MonthlyLimit private (value: Double)
object MonthlyLimit:
def apply(value: Double): Option[MonthlyLimit] = value match
case d if d <= 0d => None
case d if d > 10000d => Some(new MonthlyLimit(10000d))
case _ => Some(new MonthlyLimit(value))
sealed trait Card
case class CreditCard(monthlyLimit: MonthlyLimit) extends Card
case object DebitCard extends Card
val maybeCard: Option[Card] = for
monthlyLimit <- MonthlyLimit(1000)
yield CreditCard(monthlyLimit)if x != null или if isInvalid проверки)Типизирано ADT, при което някои product типовете са дефинирани само за специфични типове
Nicolas Rinaudo: Far more than you’ve ever wanted to know about ADTs