관리 메뉴

HAMA 블로그

스칼라 강좌 (21) - Option 과 Either 본문

Scala

스칼라 강좌 (21) - Option 과 Either

[하마] 이승현 (wowlsh93@gmail.com) 2016. 9. 29. 19:50

Option

값이 있거나 또는 없거나 한 상태를 나타낼 수 있는 타입이다.
값이 담겨져 있는 Option 의 하위 타입은 Some[T] 이며, 값이 없으면 None  이다.
Option 은 Try, Future 등과 함께 대표적인  모나딕컬렉션 이다. "컬렉션" 이다.

보통 Option 을 떠올리면 2가지를 생각해야한다.

1. null 을 안전하게 대체하기 위해 만들어진 것. 
-> 사용자에게 주의를 다시 한번 당부하는 것으로, null 예외가 발생할 확률을 없앤다.

2. 연속체인에서 안정적으로 사용하기 위한 것
-> 연속으로 계산되는 상황에서 안정적으로 실행된다. 즉 중간에 문제가 생기는것을 방어한다. 주의 할 것은 방어가 되는 함수는 따로 있다는 것이며 아래 표에서 자세히 설명된다. 

Option 이 사용되는 경우 

val numbers = Map("one" -> 1, "two" -> 2)
val h2 : Option[Int] = numbers.get("two")

이 경우 h1 에는 값이 담겨져 있는 Option 을 받을 것이다. 즉 Some 타입을 받을 것이고

val numbers = Map("one" -> 1, "two" -> 2)
val h3 : Option[Int] = numbers.get("three")

이 경우 h3 에 해당 되는 값이 없기 때문에 Option 은 None 이 될 것이다. 

Option 에서 값 가져오기 (get 과 isDefined 사용하기)

val h3 : Option[Int] = numbers.get("three")

이 경우 h3 이 Some 인지 None 인지 어떻게 알까? 확인하고 사용해야지 않을가? 
그때 isDefined 메소드를 사용한다. 
(반대 개념의  isEmpty 도 있다.)

if (h3.isDefined)
println (h3.get)

요렇게  확인해서 값을 사용 할 수 있다.  Option 타입에서 실제 값을 가져오는 함수는 get 이다. 

getOrElse 로 사용하기

def testOption(o : Option[Int]) = {

println(o.getOrElse("nothing"))
}

getOrElse 를 사용하여 값이 있으면 그 값을 사용하고 , 없으면 인자로 넘긴 "nothing" 을 사용하게 한다.

패턴 매칭으로 로 사용하기

def testOption(o : Option[Int]) = {

val result = o match {
case Some(n) => n
case None => "nothing" }
}

match 를 사용하여 값이 있으면 즉 Some(n) 으로 매칭되면 값 사용 , 없으면 "nothing" 을 사용하게 한다. 

Option 타입의 파라미터 사용

def testOption(o : Option[Int]) = {
    ...
}

testOption(Some(10))

옵션타입을 인자로 받는 함수에 값을 넘길때는 값을 직접 넘길 수 없다. Some 타입으로 만들어서 넘긴다.

Option 타입을 map 으로 연결 해보자.

case class Employee(name: String, department: String)

def lookupByName(name: String) : Option[Employee] = ...

val joeDepartment: Option[String] = lookupByName("joe").map(_.department)

이렇게 map 으로 연결 할 수 있다. 즉 map 은 Option 타입을 스스로 변경하여 적용한다.
근데 여기서 None 이 맵으로 들어 가면 어떻게 될까? 그냥 나머지 계산이 취소되어서 아무것도 안한다.

Option 은 스칼라에서의 가장 기본적인 모나드라고 한다.
추가적으로 Try, Future 등도 대표 모나딕컬렉션이다. 

안전한 Option 추출 정리 

 fold

nextOption.fold(-1)(x=>x) 

Some(이 경우 내장값)인 경우 주어진 함수로부터 추출한 값을,None인 경우 시작값을 반환함,foldLeft,foldRight,reduceXXX 메소드로도 Option 을 그 내장된 값 아니면 계산된 값으로 축소할 수 있음   

 getOrElse

nextOption getOrElse 5 또는
nextOption getOrElse {
   println("error!"); -1 }

Some의 값을 반환하거나 아니면 이름 매개변수의 결과를 반환함 

 orElse

nextOption orElse nextOption 

실제로 값을 추출하지는 않지만,None인 경우 값을 채우려함. Option이 비어 있지 않으면 이 Option을 반환하고, 그렇지 않은 경우 주어진 이름 매개변수로부터 Option 을 반환함 

match 표현식 

nextOption match { case Some(x) =>x;
                       case None => -1 } 

값이 있는 경우 매치 표현식을 사용하여 그 값을 처리함, Some(x) 표현식은 그 데이터를 추출하여 매치 표현식의 결과값으로 사용되거나 또 다른 변환에 재사용할 수 있는 지정된 값'x' 에 넣음 

* 러닝스칼라 (제이슨스와츠,제이펍 발생) 에서 발췌

Either 

둘 중 하나의 값을 가질 수 있는 타입이다.

Either 에 값 담기 

def eitherTest(num: Option[Int]): Either[String, Int] = num match {
case Some(n) => Right(n)
case None => Left("Error! Number is missing!")
}


eitherTest(Some(7))

eitherTest 메소드를 살펴보자. 
인자로 제대로 된 값이 들어오면 Right 즉 Either 의 오른쪽에 담고
인자에 제대로 된 값이 안 들어오면 Left 즉 Either 의 왼쪽에 값을 담는다.  

Either 값 사용하기 

val res = eitherTest(Some(7))
if( res.isRight )     println("Number is %s".format(res.right.get))
else if( res.isLeft)     println("Error message => %s".format(res.left.get))

eitherTest 메소드를 호출해서 받는 값 res 는  Either[String, Int] 타입인데  어느쪽에 제대로 된 값이 들어 있는 지 확인하기 위해서 res.isRight / res.isLeft 를 사용했다.

패턴 매칭으로 사용하기 

val result = eitherExample(Some(7)) match {
case Right(num) => num
case Left(err) => err
}

다음 처럼 패턴 매칭을 사용 할 수 도 있다. 


레퍼런스:

러닝 스칼라
프로그래밍 인 스칼라

Comments