-
Notifications
You must be signed in to change notification settings - Fork 7
7.4.1
LazySoul edited this page Sep 24, 2016
·
3 revisions
Option은 이진 컨테이너입니다. 즉 어떤 원소를 포함하고 있거나. 그렇지 않거나 둘 중 하나입니다. Option도 우리에게 필요한 4가지 메서드를 모두 제공합니다.
sealed abstract class Option[A+] { self =>
...
def isEmpty: Boolean // Some 인이나 None이 궇구혆구현한구현한다.
final def foreach[U](f: A=> U): Unit =
if (!isEmpty) f(this.get)
final def map[B](f: A => B): Option[B] =
if (isEmtpy) None else Some(f(this.get))
final def flatmap[B](f: A => Option[B]): Option[B] =
if (isEmtpy) None else Some(f(this.get))
final def filter(p: A=>Boolean) : Option[B] =
if (isEmpty || p(this.get)) this else None
final def withFilter(p: A => Boolean): WithFilter = new WithFilter(p)
class WithFilter(p: A => Boolean) {
def map[B](f: A => B): Option[B] = self filter p map f
def flatMap[B](f: A => Ootion[B]): Option[B] = self filter p flatmap f
def foreach[U](f: A => U): Unit = self filter p foreach f
def withFilter(q: A => Boolean): WithFilter =
new WithFilter(x => p(x) && q(x))
}
}
final
키워드는 서브클래스가 이 구현을 오버라이딩 하지 못하도록 막는다.
Option
은 비어있거나 (None) 그렇지 않거나 (Some), 둘 중 하나다.
val results: Seq[Option[Int]] = Vector(Some(10), None, Some(20))
val result2 = for {
Some(i) <- results
} yield(2 * i)
//반환 Seq[Int] = Vector(20, 40)
Some(i) <- list 패턴은 results 의 원소와 매치되면서, None값을 제거하고 Some 값 안의 정수를 뽑아낸다.
위 코드처럼 변환 규칙을 적용해서 각각의 pat <- expr 식을 withFilter식으로 바꾼것이다.
val results2b = for {
Some(i) <- results withFilter {
case Some(i) => true
case None => false
} yield (2 * 1)
//반환 : results2b: List[Int] = List(20, 40)
바깥쪽의 for { x <- y } yield (z) 식을 map 호출로 바꾼다.
val results2c = results withFilter {
case Some(i) => true
case None => false
} map {
case Some(i) => (2 * i)
}
//반환 : results2c : List[Int] = List(20,40)
실제로는 map 식에서 컴파일러가 경고를 발생시킨다.
<<console>:9: warring: match may not be exhaustive.
It would fail on the following input : None
} map {
^
보통은 map에 case None => ...절이 없는 부분함수를 넘기는 것은 위험하다. None이 들어오면 MatchError예외가 던져질 것이다. 하지만 withFilter 호출이 이미 None 원소를 제거했기 때문에 그 예외는 발생할 수 없다.
독립적인 작업을 여럿 실행하면서 결과가 없는 경우를 무시하고 정상적인 결과를 취합하는 대신, 의존 관계가 있는 여러 단계의 작업을 순차적으로 실행하면서, None이 발생하자마자 전체 과정을 중단하고 싶은 경우를 생각해보자.
def positive(i: Int): Option[Int] =
if (i > 0) Some(i) else None
for {
i1 <- positive(5)
i2 <- positive(10 * i1)
i3 <- positive(25 * i2)
i4 <- positive(2 * i3)
} yield (i1 + i2 + i3 + i4)
// Returns: Option[Int] = Some(3805)
for {
i1 <- positive(5)
i2 <- positive(-1 * i1) // <1> EPIC FAIL!
i3 <- positive(25 * i2) // <2>
i4 <- positive(-2 * i3) // EPIC FAIL!
} yield (i1 + i2 + i3 + i4)
// Returns: Option[Int] = None