SW 설계/스칼라

스칼라: Sealed, Final, Option, Try 클래스

yztech 2021. 9. 25. 04:12
반응형

Sealed

sealed가 붙은 class는 선언된 파일 안에서만 상속이 가능합니다.

sealed 의 자식은 sealed 가 아니므로, 주로 final 과 함께 사용됩니다.

sealed의 한 예로,

OptionSome, None의 두 개의 자식이 존재하고,

TrySuccessFailure의 두개의 자식이 존재합니다.

둘은, sealed로 선언되어 있으므로, 같은 파일 내에서 선언한 Some, NoneSuccess, FailureOptionTry의 자식이 될 수 있습니다.

또한 이들은 상속할 수 없는 final case classobject로 선언하여 추가 상속을 막고 있습니다.

 sealed abstract class Option[+A] extends Product with Serializable {
     ...

 final case class Some[+A](@deprecatedName('x, "2.12.0") value: A) extends Option[A] {
   def isEmpty = false                                                                
   def get = value                                                                    

   @deprecated("Use .value instead.", "2.12.0") def x: A = value
 }

 case object None extends Option[Nothing] {                                           
   def isEmpty = true                                                                 
   def get = throw new NoSuchElementException("None.get")                             
 }

Final

final은 최종을 의미하는데, 더 이상 변경 불가를 의미합니다.

final 수정자는 클래스 멤버 혹은 위 예와 같이 클래스 정의에 사용할 수 있습니다.

만약 클래스 멤버에 적용한 경우, 하위 클래스에서 override (재정의)할 수 없다는 것이고,

만약 클래스 정의에 적용한 경우, 하위 클래스가 inherit (상속)할 수 없다는 것을 의미합니다.

Option: Some, None

Option은 스칼라 컬렉션 중의 하나입니다.

Option 클래스는 값이 있거나, 없거나 한 상태를 나타내는 클래스입니다.

값이 있으면 Some이 되고, 값이 없으면 None이 됩니다.

None은 아무것도 없다는 것을 표현하기 위해 사용하고, null 포인터 예외를 회피하기 위한 클래스입니다.

Option에서 값의 있는지 없는지를 확인하기 위해 isDefined 혹은 isEmpty 메소드를 사용할 수 있습니다.

이는 case 문으로 부분함수를 정의할 때, 부분함수가 해당 조건에 대해 정의되어 있는지 확인하기 위해 isDefinedAt 메소드를 사용하는 것과 같습니다.

아래 예를 들어보겠습니다. 3명의 학생이 있고, 그들의 ID 번호를 확인하는 코드를 작성해보겠습니다.

val studentIds = Map(
	"daniel" -> 1, 
    "mat" -> 2, 
    "chris" -> 3)
val id1: Option[Int] = studentIds.get("daniel")
val id2: Option[Int] = studentIds.get("jane")

위 코드에서 id1은 Int 형의 Option 타입으로 정해져 있고, daniel이 있으므로, id1에는 Some 타입이 들어갑니다.
id2는 jane이 없으므로, None 이 들어가게 됩니다.

이들의 값의 유무를 확인해서 출력하려면 아래와 같이 구현할 수 있습니다.

if(id1.isDefined)
    println(id1.get)

if(id2.isDefined)
    println(id2.get)

위 코드는 id1만 Some 타입이므로 값을 출력하고, id2는 None 타입이므로 값을 출력하지 않게 됩니다.

만약, 값의 존재여부에 따라, 학생인지 확인하도록 다르게 동작하게 하려면, 아래와 같이 부분함수를 사용하여 구현할 수 있습니다.

def testId(id: Option[Int]) = {
    val result = id match {
        case Some(n) => n
        case None => "not a student"
    }    
}

지금까지 보았듯이, 스칼라는 DRY를 따르는 매우 좋은 언어입니다.

문제를 해결하는 데 한가지 방식의 표현이 아닌 다양한 방법으로 표현이 가능하고,

또한 구현을 위한 더미 코드를 줄여서 함축성이 매우 좋은 언어라고 생각할 수 있습니다.

반응형