본문 바로가기
Language/Kotlin

[Kotlin IN ACTION] - Kotlin 스마트 캐스트

by Jman 2022. 7. 9.

2.3.5  스마트 캐스트 : 타입 검사와 타입 캐스트를 조합

 

(1 + 2) + 4 라는 간단한 산술식을 계산하는 함수를 만들어보자.

식을 트리구조로 저장할 것이다. 

노드는 합계(Sum) 나 수(Num) 중 하나다. 

Num은 항상 말단 노드지만, Sum 은 자식이 둘 있는 중간 노드다.

Sum 노드의 두 자식은 덧셈의 두 인자다. 

Expr 인터페이스에는 두 가지 구현 클래스가 존재한다.

따라서 식을 평가하려면 두 가지 경우를 고려해야 한다.

  • 어떤 식이 수라면 그 값을 반환한다.
  • 어떤 식이 합계라면 좌항과 우항의 값을 계산한 다음에 그 두 값을 합한 값을 반환한다.

 

[Java]

// [Java] - 식을 표현하는 클래스 계층

interface Expr {}

class Num implements Expr {
    int value;

    public Num(int value) {
        this.value = value;
    }
}

class Sum implements Expr {
    Expr left;
    Expr right;

    public Sum(Expr left, Expr right) {
        this.left = left;
        this.right = right;
    }
}



public class test {

    // [Java] - if 연쇄를 사용해 식을 계산하기    
    public static int eval(Expr expr) {
        if (expr instanceof Num) {
            return ((Num) expr).value;
        } else if (expr instanceof Sum) {

            return eval(((Sum) expr).left) + eval(((Sum) expr).right);
        } else {
            throw new IllegalArgumentException("Unknown expression");
        }
    }
    
    // 호출 부분!
    public static void main(String[] args) {
        System.out.println(eval(new Sum(new Sum(new Num(1), new Num(2)), new Num( 4))));
    }


}

[Kotlin]

// [Kotlin] - 식을 표현하는 클래스 계층

interface Expr
// value 라는 프로퍼티만 존재하는 단순한 클래스로 Expr 인터페이스를 구현한다.
class Num(val value : Int) : Expr

// Expr 타입의 객체라면 어떤 것이나 Sum 연산의 인자가 될 수 있다.
// 따라서, Num 이나 다른 Sum 이 인자로 올 수 있다.
class Sum(val left : Expr, val right : Expr) : Expr



// [Kotlin] - if 연쇄를 사용해 식을 계산하기
fun eval(e: Expr) : Int {
    if (e is Num) {
        return e.value
    }else if (e is Sum) {
        return eval(e.right) + eval(e.left) // 변수 e에 대해서 스마트 캐스트를 사용한다.
    }else {
        throw IllegalArgumentException("Unknown expression")
    }
}

// [Kotlin] - if 중첩 대신 when 사용하기, 바로 리턴값을 대입하기
fun eval(e: Expr) : Int = 
     when (e) {
        is Num -> {
            e.value
        }
        is Sum -> {
            eval(e.right) + eval(e.left) // 변수 e에 대해서 스마트 캐스트를 사용한다.
        }
        else -> {
            throw IllegalArgumentException("Unknown expression")
        }
    }

// 호출 부분
fun main() {
    println(eval(Sum(Sum(Num(1), Num(2)), Num(4))))
}

 

어떤 변수가 원하는 타입인지? 일단 is 로 검사하고 나면,
굳이 변수를 원하는 타입으로 캐스팅 하지 않아도, 마치 처음부터 그 변수가 원하는 타입으로 선언된 것처럼 사용할 수 있다.
하지만, 실제로는 컴파일러가 캐스팅을 수행해준다.
이를 스마트 캐스트라고 부른다.