gimmesilver's blog

Agbird.egloos.com

포토로그



scala 에서 사용하는 세 가지 선언문... 프로그래밍

 scala 는 타입 추론 기능이 있기 때문에 객체 선언시 해당 객체의 타입을 굳이 지정할 필요가 없습니다. 대신 객체 선언 시 객체의 특성에 따라 각기 다른 지정자를 이름 앞에 표시해야 하는데 그 종류는 var, val, def 입니다.
 var 는 variable 의 약자로 말그대로 가변 객체를 선언할 때 사용합니다. 예를 들어 어떤 정수 변수 x를 선언하려면 다음과 같이 합니다.
 var x = 1

 val 은 value 의 약자로 값 즉, 불변 객체를 선언할 때 사용합니다. 자바의 final 객체나 C++의 const 객체 쯤으로 생각하면 됩니다. 선언 예는 아래와 같습니다.
 val y = x+1

 def 는 함수 객체를 선언할 때 사용합니다. 스칼라는 '자바 프로그래머를 위한 함수형 언어 스칼라'라는 글에서 언급했듯이 함수조차도 객체로 취급합니다. 그리고 이런 함수 객체를 선언할 때는 def 라는 지정자를 사용합니다. 선언 예는 아래와 같습니다. 
 def z = x+1

 scala 인터프리터에서 위 선언문들을 차례로 입력했다면 다음과 같이 각각의 객체 값을 확인해볼 수 있습니다.
x
Int=1

y
Int=2

z
Int=2

 이 때 x는 가변 객체이므로 다음과 같이 객체의 값을 변경할 수 있습니다.
x=3

 이제 x의 값은 3이 됩니다. 하지만 y나 z는 한번 객체를 선언하고 나면 그 값을 바꿀 수 없습니다. 따라서 y=3 혹은 z=3 을 하게 되면 에러가 발생합니다. 즉, val 이나 def 로 선언한 객체는 불변객체입니다. 그럼 여기서 val 과 def 의 차이는 뭘까요?
차이는 우변식의 평가가 언제이루어지느냐입니다. val 로 선언한 객체는 선언 시점에 우변식을 평가한 값을 y에 저장하지만 def 로 선언한 객체는 해당 객체 값을 필요로하는 시점에 우변식을 평가한 후 결과값을 반환합니다. 예를 들어

var x = 1
val y = x+1
def z = x+1

 이렇게 선언되어 있다면 x나 y는 선언 시점에 우변식의 값이 저장되지만 z는 우변식의 결과값이 저장되는 것이 아니라 우변식 자체를 저장하게 됩니다. 따라서 x의 값은 1이고 y의 값은 2이지만 z의 값은 2가 아니라 x+1 이라는 식 그 자체입니다. 물론 이 시점에서 z의 객체값을 참조하게 되면 역시 y와 동일한 2값을 반환합니다. 하지만 여기서 만약 x = 2 라고 하게 되면 x의 값은 이제 2가 되며 y 의 값은 선언 시점에 정해졌기 때문에 그대로 2입니다. 하지만 z의 경우는 이제 x값이 2이므로 이 때 z값을 참조하면 3이 됩니다. 지금까지의 설명을 소스로 풀어보면 다음과 같습니다.

object AssignTest {
    def main(args: Array[String]) {
        var x = 1
        val y = x+1
        def z = x+1
        println(x+","+y+","+z) // 1,2,2 출력

        x = 3
        println(x+","+y+","+z) // 3,2,4 출력
    }
}

재밌는 점은 함수자체도 객체로 취급되기 때문에 var 나 val 로 선언한 객체에서조차도 함수를 값으로 받을 수 있다는 점입니다. 즉, 다음과 같은 선언도 유효합니다.
var x = println("Hello")

이 경우 x는 var 객체이고 var 객체는 선언 혹은 할당 시점에 우변식을 계산하기 때문에 선언 시점에 "Hello" 라는 문자열을 화면에 출력합니다. 예를 들어,

object AssignTest2 {
    def main(args: Array[String]) {
        println("assignment start...")
        var x = println("This is var")
        val y = println("This is val")
        def z = println("This is def")
        println("assignment end...")

        x = println("This is another var")
        z
    }
}

위 소스의 결과는 다음과 같습니다.

assignment start...
This is var
This is val
assignment end...
This is another var
This is def

그러면 x나 y가 가지고 있는 값은 뭘까요? println() 같은 IO 함수들은 호출 시 IO 작업을 side effect로 수행할 뿐 어떤 값을 반환할 필요는 없습니다만 객체이기 때문에 어떤 값을 가지고 있어야 합니다. scala에서는 이처럼 반환값이 필요없는 함수들은 () 라는 값을 갖도록 정의했습니다. 자바의 void 와 동일한 의미입니다만 자바에서는 void 가 단순히 값이 없음을 의미하는 반면 scala의 ()는 '값이 없음' 이라는 값을 의미합니다. 따라서 위 소스의 x나 y의 값은 () 입니다.


덧글

  • 스갈라 2008/04/18 00:18 # 삭제 답글

    매우 좋은 글입니다. 다음 글이 기대 됩니다.
  • silverbird 2008/04/18 14:29 # 답글

    // 스갈라
    제가 게을러서 언제 다음 글이 올라올지 기약이 없답니다...
댓글 입력 영역