Sök…


Sammansättning

Delfunktioner används ofta för att definiera en totalfunktion i delar:

sealed trait SuperType
case object A extends SuperType
case object B extends SuperType
case object C extends SuperType

val pfA: PartialFunction[SuperType, Int] = {
  case A => 5
}

val pfB: PartialFunction[SuperType, Int] = {
  case B => 10
}

val input: Seq[SuperType] = Seq(A, B, C)

input.map(pfA orElse pfB orElse {
  case _ => 15
}) // Seq(5, 10, 15)

Vid denna användning försöks de partiella funktionerna i ordningsföljd för sammankoppling med orElse metoden. Vanligtvis tillhandahålls en slutlig partiell funktion som matchar alla återstående fall. Sammantaget fungerar kombinationen av dessa funktioner som en total funktion.

Detta mönster används vanligtvis för att separera problem där en funktion effektivt kan verka en avsändare för olika kodvägar. Detta är vanligtvis till exempel i mottagningsmetoden för en Akka-skådespelare .

Användning med "samla"

Medan partiell funktion ofta används som bekväm syntax för totala funktioner, genom att inkludera en slutlig jokerteckenmatchning ( case _ ), är vissa partier i vissa metoder viktiga. Ett mycket vanligt exempel på idiomatisk Scala är collect metod, som definieras i Scala samlingar biblioteket. Här tillåter delfunktioner de vanliga funktionerna för att undersöka elementen i en samling för att kartlägga och / eller filtrera dem i en kompakt syntax.

Exempel 1

Förutsatt att vi har en kvadratrotfunktion definierad som partiell funktion:

val sqRoot:PartialFunction[Double,Double] = { case n if n > 0 => math.sqrt(n) }

Vi kan åberopa det med collect :

List(-1.1,2.2,3.3,0).collect(sqRoot)

effektivt utföra samma operation som:

List(-1.1,2.2,3.3,0).filter(sqRoot.isDefinedAt).map(sqRoot)

Exempel 2

sealed trait SuperType // `sealed` modifier allows inheritance within current build-unit only
case class A(value: Int) extends SuperType
case class B(text: String) extends SuperType
case object C extends SuperType

val input: Seq[SuperType] = Seq(A(5), B("hello"), C, A(25), B(""))

input.collect {
  case A(value) if value < 10   => value.toString
  case B(text) if text.nonEmpty => text
} // Seq("5", "hello")

Det finns flera saker att notera i exemplet ovan:

  • Vänster sida av varje mönster matchar effektivt element som ska bearbetas och inkluderas i utgången. Allt värde som inte har ett matchande case utelämnas helt enkelt.
  • Den högra sidan definierar den fallspecifika behandling som ska tillämpas.
  • Mönstermatchning binder variabel för användning i skyddsuttalanden ( if klausulerna) och höger sida.

Grundläggande syntax

Scala har en speciell typ av funktion som kallas en partiell funktion , som utökar normala funktioner - vilket innebär att en PartialFunction instans kan användas varhelst Function1 förväntas. Partiella funktioner kan definieras anonymt med hjälp av case syntax som också används i mönstermatchning :

val pf: PartialFunction[Boolean, Int] = {
  case true => 7
}

pf.isDefinedAt(true) // returns true
pf(true) // returns 7

pf.isDefinedAt(false) // returns false
pf(false) // throws scala.MatchError: false (of class java.lang.Boolean)

Som framgår av exemplet behöver en partiell funktion inte definieras över hela domänen för dess första parameter. En standardinställning av Function1 antas vara total , vilket innebär att den definieras för alla möjliga argument.

Användning som en total funktion

Partiella funktioner är mycket vanliga i idiomatiska Scala. De används ofta för sin bekväm case baserad syntax för att definiera den totala funktioner över egenskaper :

sealed trait SuperType // `sealed` modifier allows inheritance within current build-unit only
case object A extends SuperType
case object B extends SuperType
case object C extends SuperType

val input: Seq[SuperType] = Seq(A, B, C)

input.map {
  case A => 5
  case _ => 10
} // Seq(5, 10, 10)

Detta sparar ytterligare syntaxen för en match uttalande i en vanlig anonym funktion. Jämföra:

input.map { item => 
  item match {
    case A => 5
    case _ => 10
  }
} // Seq(5, 10, 10)

Det används också ofta för att utföra en nedbrytning av parametrar med hjälp av mönstermatchning, när en tupel eller en fallklass överförs till en funktion:

val input = Seq("A" -> 1, "B" -> 2, "C" -> 3)

input.map { case (a, i) =>
   a + i.toString
} // Seq("A1", "B2", "C3")

Användning för att extrahera tuples i en kartfunktion

Dessa tre kartfunktioner är likvärdiga, så använd den variation som ditt team tycker är mest läsbart.

val numberNames = Map(1 -> "One", 2 -> "Two", 3 -> "Three")

// 1. No extraction
numberNames.map(it => s"${it._1} is written ${it._2}" )

// 2. Extraction within a normal function
numberNames.map(it => {
    val (number, name) = it
    s"$number is written $name"
})

// 3. Extraction via a partial function (note the brackets in the parentheses)
numberNames.map({ case (number, name) => s"$number is written $name" })

Partifunktionen måste matcha alla inmatningar : alla fall som inte matchar kommer att kasta ett undantag vid körning.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow