A partial function of type PartialFunction[A, B]
is a unary function where the domain does not necessarily include all values of type A
. The function isDefinedAt allows to test dynamically if a value is in the domain of the function.
Even if isDefinedAt
returns true for an a: A
, calling apply(a)
may still throw an exception, so the following code is legal:
val f: PartialFunction[Int, Any] = { case x => x / 0 } // ArithmeticException: / by zero
It is the responsibility of the caller to call isDefinedAt
before calling apply
, because if isDefinedAt
is false, it is not guaranteed apply
will throw an exception to indicate an error condition. If an exception is not thrown, evaluation may result in an arbitrary value.
The usual way to respect this contract is to call applyOrElse, which is expected to be more efficient than calling both isDefinedAt
and apply
.
The main distinction between PartialFunction
and scala.Function1 is that the user of a PartialFunction
may choose to do something different with input that is declared to be outside its domain. For example:
val sample = 1 to 10
def isEven(n: Int) = n % 2 == 0
val eveningNews: PartialFunction[Int, String] = {
case x if isEven(x) => s"$x is even"
}
// The method collect is described as "filter + map"
// because it uses a PartialFunction to select elements
// to which the function is applied.
val evenNumbers = sample.collect(eveningNews)
val oddlyEnough: PartialFunction[Int, String] = {
case x if !isEven(x) => s"$x is odd"
}
// The method orElse allows chaining another PartialFunction
// to handle input outside the declared domain.
val numbers = sample.map(eveningNews orElse oddlyEnough)
// same as
val numbers = sample.map(n => eveningNews.applyOrElse(n, oddlyEnough))
val half: PartialFunction[Int, Int] = {
case x if isEven(x) => x / 2
}
// Calculating the domain of a composition can be expensive.
val oddByHalf = half.andThen(oddlyEnough)
// Invokes `half.apply` on even elements!
val oddBalls = sample.filter(oddByHalf.isDefinedAt)
// Better than filter(oddByHalf.isDefinedAt).map(oddByHalf)
val oddBalls = sample.collect(oddByHalf)
// Providing "default" values.
val oddsAndEnds = sample.map(n => oddByHalf.applyOrElse(n, (i: Int) => s"[$i]"))
Attributes
- Note
-
Optional Functions, PartialFunctions and extractor objects can be converted to each other as shown in the following table.
How to convert ...
to a PartialFunction
to an optional Function
to an extractor
from a PartialFunction
from optional Function
from an extractor
{ case extractor(x) => x }
extractor.unapply _
- Companion
- object
- Source
- PartialFunction.scala
- Graph
-
- Supertypes
- Known subtypes
-
class IntMap[T]class LongMap[T]class LongMap[V]class SystemPropertiestrait Seq[A]trait Seq[A]class AbstractSeq[A]class ArraySeq[A]class ofBooleanclass ofByteclass ofCharclass ofDoubleclass ofFloatclass ofIntclass ofLongclass ofRef[T]class ofShortclass ofUnitclass LazyList[A]class List[A]class ::[A]object Nil.typeclass NumericRange[T]class Exclusive[T]class Inclusive[T]class Queue[A]class Rangeclass Exclusiveclass Inclusiveclass Stream[A]class Cons[A]object Empty.typeclass Vector[A]class WrappedStringtrait IndexedSeq[A]trait LinearSeq[A]trait Seq[A]class AbstractSeq[A]class AbstractBuffer[A]class ArrayBuffer[A]class ArrayDeque[A]class Queue[A]class Stack[A]class ListBuffer[A]class UnrolledBuffer[T]class ArraySeq[T]class ofBooleanclass ofByteclass ofCharclass ofDoubleclass ofFloatclass ofIntclass ofLongclass ofRef[T]class ofShortclass ofUnitclass StringBuildertrait Buffer[A]trait IndexedBuffer[A]trait IndexedSeq[T]class AnyAccumulator[A]class DoubleAccumulatorclass IntAccumulatorclass LongAccumulatorclass AbstractSeq[A]trait IndexedSeq[A]trait LinearSeq[A]
- Self type
-