Scala Language
부분 함수
수색…
구성
부분 함수는 종종 부분의 전체 함수를 정의하는 데 사용됩니다.
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)
이 용도에서는 부분 함수가 orElse
메서드와 연결된 순서로 시도됩니다. 일반적으로 나머지 부분의 모든 경우와 일치하는 마지막 부분 함수가 제공됩니다. 집합 적으로, 이들 기능의 결합은 전체 기능으로 작용합니다.
이 패턴은 일반적으로 기능이 서로 다른 코드 경로의 디스패처를 효과적으로 작동시킬 수있는 우려를 분리하는 데 사용됩니다. 이는 Akka Actor 의 수신 방법과 같이 일반적입니다.
`collect`와 함께 사용
부분 함수는 전체 함수에 대한 편리한 구문으로 사용되는 경우가 많지만 마지막 와일드 카드 일치 ( case _
)를 포함하여 일부 함수에서는 부분 함수가 중요합니다. 관용적 인 스칼라에서 가장 일반적인 예는 스칼라 컬렉션 라이브러리에 정의 된 collect
메서드입니다. 여기서 부분 함수를 사용하면 컬렉션의 요소를 검사하여 하나의 압축 구문으로 매핑 및 / 또는 필터링하는 일반적인 기능을 사용할 수 있습니다.
예제 1
부분 함수로 정의 된 제곱근 함수가 있다고 가정합니다.
val sqRoot:PartialFunction[Double,Double] = { case n if n > 0 => math.sqrt(n) }
우리는 collect
combinator로 호출 할 수 있습니다 :
List(-1.1,2.2,3.3,0).collect(sqRoot)
효과적으로 다음과 같은 작업을 수행합니다.
List(-1.1,2.2,3.3,0).filter(sqRoot.isDefinedAt).map(sqRoot)
예제 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")
위의 예에서주의해야 할 몇 가지 사항이 있습니다.
- 각 패턴 일치의 왼쪽은 처리 할 요소를 효과적으로 선택하여 출력에 포함시킵니다. 일치하는
case
가없는 값은 단순히 생략됩니다. - 오른쪽은 적용 할 사례 별 처리를 정의합니다.
- 패턴 일치는 가드 문 (
if
절)과 오른쪽에서 사용할 변수를 바인딩합니다.
기본 구문
스칼라는 partial 함수라고 불리는 특별한 함수 를 가지고 있는데, 이는 일반적인 함수 를 확장한다. Function1
이 예상되는 곳이면 PartialFunction
인스턴스를 사용할 수있다. 패턴 매칭 에서도 사용되는 case
구문을 사용하여 부분 함수를 익명으로 정의 할 수 있습니다.
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)
예제에서 볼 수 있듯이 부분 함수는 첫 번째 매개 변수의 전체 도메인에 정의 할 필요는 없습니다. 표준 Function1
인스턴스는 가능한 모든 모든 인수에 대해 정의된다는 것을 의미하는 total 이라고 가정합니다.
총 기능으로 사용
부분 함수는 관용적 인 스칼라에서 매우 일반적입니다. 이들은 종종 특성에 대한 총 기능을 정의하기 위해 편리한 case
기반 구문에 사용됩니다.
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)
이렇게하면 일반 익명 함수에서 match
문의 추가 구문을 저장합니다. 비교:
input.map { item =>
item match {
case A => 5
case _ => 10
}
} // Seq(5, 10, 10)
또한 튜플이나 case 클래스가 함수에 전달 될 때 패턴 매칭을 사용하여 매개 변수 분해를 수행하는 데 자주 사용됩니다.
val input = Seq("A" -> 1, "B" -> 2, "C" -> 3)
input.map { case (a, i) =>
a + i.toString
} // Seq("A1", "B2", "C3")
지도 함수에서 튜플을 추출하는 용도
이 세 가지 맵 기능은 동일하므로 팀이 가장 쉽게 읽을 수있는 변형을 사용하십시오.
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" })
부분 함수 는 모든 입력과 일치해야합니다. 일치 하지 않는 경우는 런타임에 예외를 throw합니다.