devcken.io

Thoughts, stories and ideas.

Scala Type Bounds: Upper Bounds, Lower Bounds and View Bounds

원문: Scala Type Bounds: Upper Bounds, Lower Bounds and View Bounds

이전 포스트에서, 스칼라 변성에 관해 자세히 알아보았습니다. 이번 포스트에서는, "스칼라 타입 바운드"에 대해서 알아보도록 하겠습니다.

스칼라의 타입 바운드란 무엇인가?

스칼라의 타입 바운드는 타입 파라메터 혹은 타입 변수에 대한 제한을 말합니다. 타입 바운드를 사용하여, 타입 변수의 범위(limit)을 정의할 수 있습니다.

스칼라 타입 바운드의 이점

스칼라 타입은 다음과 같은 이점을 제공합니다:

  • 타입에 안전한 애플리케이션 개발

스칼라 타입 바운드

스칼라는 다음과 같은 타입 변수의 타입 바운드를 지원합니다:

  • 스칼라 상위 바운드
  • 스칼라 하위 바운드
  • 스칼라 뷰 바운드

다음 섹션에서 예제를 가지고 이런 개념들에 대해 좀 더 자세히 알아보도록 하겠습니다.

스칼라 상위 바운드

스칼라에서, 아래 그림처럼 타입 파라메터에 상위 바운드를 정의할 수 있습니다.

설명

여기서 T는 타입 파라메터이고 S는 타입입니다. [T <: S]와 같이 상위 바운드를 선언한다는 것은 타입 파라메터 TS와 동일하거나 S의 하위 타입이 되어야 한다는 것입니다.

예제1

[T <: Ordered[T]]

여기서 우리는 타입 파라메터 T에서 Ordered[T] 타입으로의 상위 바운드를 정의했습니다. 그러면 TOrdered 혹은 Ordered 타입의 하위 타입됩니다.

예제2

다음은 스칼라 상위 바운드를 설명하기 위한 스칼라 프로그램입니다.

class Animal  
class Dog extends Animal  
class Puppy extends Dog

class AnimalCarer{  
  def display [T <: Dog](t: T){
    println(t)
  }
}

object ScalaUpperBoundsTest {  
  def main(args: Array[String]) {

    val animal = new Animal
    val dog = new Dog
    val puppy = new Puppy

    val animalCarer = new AnimalCarer

    //animalCarer.display(animal)
    animalCarer.display(dog)
    animalCarer.display(puppy)
  }
}

이 프로그램은 다음 라인을 주석 처리해야 잘 동작합니다.

해당 라인의 주석을 제거하고 다시 해보면, 컴파일 오류가 발생할 겁니다. 왜냐하면, 아래와 같이 상위 바운드를 정의했기 때문이죠:

class AnimalCarer{  
  def display [T <: Dog](t: T){
    println(t)
  }
}

여기서 [T <: Dog]를 정의했는데 이것은 display 메서드가 Dog 클래스의 객체 혹은 Dog 클래스의 하위 타입(즉, Puppy)만 받아들인다는 것을 의미합니다. 그것이 Dog 슈퍼 클래스를 전달하면 "Type Mismatch" 컴파일 오류가 발생하는 이유입니다.

스칼라 하위 바운드

스칼라에서, 아래 보이는 것처럼 타입 파라메터에 하위 바운드를 정의할 수 있습니다:

설명

여기서 T가 타입 파라메터고 S가 타입입니다. [T >: S]처럼 하위 바운드를 설정한다는 것은 해당 타입 파라메터 TS와 같거나 S의 상위 타입이어야 한다는 것을 의미합니다.

예제1

[T >: Ordered[T]]

여기서 타입 파라메터 T에서 Ordered[T] 타입으로의 하위 바운드를 정의했습니다. 그러면 TOrdered 혹은 Ordered 타입의 상위 타입이 되어야 합니다.

예제2

class  Animal  
class Dog extends Animal  
class Puppy extends Animal

class AnimalCarer{  
  def display [T >: Puppy](t: T){
    println(t)
  }
}

object ScalaLowerBoundsTest {  
  def main(args: Array[String]) {

    val animal = new Animal
    val dog = new Dog
    val puppy = new Puppy

    val animalCarer = new AnimalCarer

    animalCarer.display(animal)
    animalCarer.display(puppy)
    animalCarer.display(dog)
  }
}

여기서 DogPuppy의 하위 타입이 아니지만, DogAnimal의 항위 타입이고 아래 보이는 것처럼 타입 파라메터 T에 "하위 바운드"를 정의했기 때문에 이 프로그램은 여전히 잘 동작합니다.

class AnimalCarer{  
  def display [T >: Puppy](t: T){
    println(t)
  }
}

이 클래스에서 하위 바운드 정의를 제거하면, 컴파일 오류가 발생하게 됩니다.

스칼라 뷰 바운드

스칼라에서, 뷰 바운드는 기존의 암시적인 변환을 자동으로 사용하고자 할 때 사용됩니다. 아래 보이는 것처럼 타입 파라메터에 뷰 바운드를 정의할 수 있습니다:

예제

다음은 (Int10 > 12와 비슷한) 관계 연산자를 가지고 문자열을 비교하는 스칼라 프로그램입니다.

class Person[T <% Ordered[T]](val firstName: T, val lastName: T) {  
  def greater = if (firstName > lastName) firstName else lastName
}

object ScalaViewBoundsTest {  
  def main(args: Array[String]) {
    val p1 = new Person("Rams","Posa")
    val p2 = new Person("Chintu","Charan")

    println(p1.greater)
    println(p2.greater)
  }
}

출력

Rams  
Chintu  

만약 스칼라 뷰 바운드 연산자인 <%를 사용하지 않는다면, 다음의 에러 메시지를 보게 될 겁니다.

error: value > is not a member of type parameter T  

이것이 스칼라의 상위 바운드, 하위 바운드 그리고 뷰 바운드의 전부입니다. 다가올 포스트에서 스칼라의 컨셉에 대해서 좀 더 알아보도록 하겠습니다.

포스트에 대해 이슈나 제안이 있다면 코멘트를 남겨주시기 바랍니다.