saltfactory's blog

Scala 시작 하기

2012/03/28 09:49 송성광


    Scala는 간결하면서도 우아하면서 일반적인 프로그래밍 패턴을 표현하기 위한 언어로 객체지향언어와 함수형 언어의 특징을 모두 사용할 수 있다. Ruby와 Python 과 같은 스크립트 언어의 장점을 사용할 수 있으면서 가장 강력한 장점으로현 Java와 완벽하게 연동할 수 있다는 것이다. 이러한 Scala는 현존하는 VM 중에서 가장 안전하다고 알려져 있는 JVM에서 동작하며 뿐만 아니라 Scala 인터프리터도 사용할 수 있다. 


    Scala의 스크립트는 컴파일하면 Java가 컴파일을하여 .class 바이너리 코드를 만들어 내듯, Scala도 .class 바이너리 코드를 만들어낸다. Java의 바이이너리 코드의 장점을 그대로 사용하기 때문에 java 프로그램에서도 Scala로 만들어진 객체를 그대로 사용할 수 있게 된다. Java로 작성하는 표현법을 Scala로 작성하면 코드량을 대량으로 줄일 수 있고 Java와 완벽하게 호환되니 Scala는 자바 개발자와 스크립트 언어 개발자나 애자일 개발자에게 인기를 얻고 있다. 최근 트위터에서 Ruby에서 Scala로 back-end 시스템 환경을 변경하면서(http://www.artima.com/scalazine/articles/twitter_on_scala.html) 국 내외 개발자들은 Scala Lanaguage에 대해서 더욱 관심을 가지기 시작했다. 국내 소프트웨어 개발 언어로 Java가 매우 큰 부분을 차지하고 있기 때문에 Scala의 도입은 매우 유연하게 될거라고 생각 든다. 실제 Scala 사이트에서 말하기를 자바의 코드와 기술을 모두 재사용할 수 있다고 말하고 있다 (Exsiting Java code and programmer skills are fully re-useable).

    또 다른 특징이자 자엄은 Scala에서 모든 것들은 Object라는 것이다. Ruby를 하면서 다른 언어에서 느끼지 못한 가장 강력하고 좋았던 것이 사용하는 모든 것이 Object이라는 것이라 데이터와 표현이 풍부하다는 것이다. Scala에서는 function 자체도 Object로 생각하는데 이렇게 만든 이유는 차츰 알아가봐야할 것 같다. 스칼라의 특징은 @Outersider 님께서 http://blog.outsider.ne.kr/476 글로 아주 잘 포스팅을 해주셨기 때문에 생략하려고 한다. Scala를 지금 시작하면서 문의를 많이 하고 있는 중이다. 

    Scala를 Mac에서 사용하기 위한 방법은 macport, homebrew 등에서 패키지를 받아서 사용하던지 Scala 공식 사이트에서 다운 받아서 사용할 수 있다. 처음에는 homebrew를 통해서 설치했는데 IntelliJ에서 Scala library를 불러오지 못하는 이유 때문에 Scala 사이트에서 코드를 받아서 압축을 풀고 PATH에 경로를 추가하였다. 최근 다운로드는 http://www.scala-lang.org/downloads 에서 받을 수 있다. 이 글을 포스팅할 때의 scalar 의 버전은 2.9.1-1이다.

    mkdir -p /Projects/Libraries/
    wget http://www.scala-lang.org/downloads/distrib/files/scala-2.9.1-1.tgz 
    tar xvfz scala-2.9.1-1.tgz


    압축을 해지하고 난뒤 SCALA_HOME과 PATH를 추가한다.

    vi ~/.profile
    export SCALA_HOME=/Projects/Libraries/scala-2.9.1-1
    export PATH=$PATH:$SCALA_HOME/bin:.


    이제 Scala를 사용할 준비가 끝났다. 매우 간단하다. 이전에 Java JDK를 설치할때가 생각난다.

    Saltfactory:Tutorial $ scala
    Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_29).
    Type in expressions to have them evaluated.
    Type :help for more information.

    scala> :quit

    아직 국내에서는 Scala에 관한 책이 없기 때문에 트위터에서 공개한 Scala School을 가지고 예제를 설명하도록 하겠다.
    Scala School에서 Start Interpreter를 하기위해서 sbt (Scala Build Tool)을 사용하는데 brew install sbt 를 해도 되지만 그냥 scala라고 실행하면 Scala 인터프리터를 사용할 수 있다.

    Expressions
     

    scala> 1 + 1
    res0: Int = 2

    인터프리터에서 연산 값은 자동적으로 res0의 이름을 만들어서 Int 값을 저장한다. 이러한 이유 때문에 res0이라는 것 자체를 다시 사용할 수 있다.

    scala> println(res0)
    2
     
    Variables / Values

    scala> var two = 1 + 1
    two: Int = 2

    res0은 다시 말해서 인터프리터가 생성하는 변수이다. 그럼 변수를 만들어서 사용해 보자. 실제 변수를 사용하면 다음과 같이 확인할 수 있다. res0에 값을 저장한 것처럼 변수 이름에 java.lang.String 타입의 값이 할당 된 것을 확인 할 수 있다.

    scala> var name = "steve"
    name: java.lang.String = steve

    scala> var name = "marius"
    name: java.lang.String = marius

    Function

    함수는 def로 정의할 수 있다. 파라미터의 이름과 타입을 지정할 수 있는데 이 방식은 ActionScript에서 파라미터를 설정하는 방법과 비슷하다. 보통 다른 언어에써는 타입을 지정하고 파라미터 이름을 설정하는 반면에 Scala에서는 이름을 지정하고 타입을 표현한다는 것이 다르다.  또한 Scala에서 세미콜론(;)은 옵션사항인데 다음과 같이 def로 function을 정의하고 내용을 설명하기 위해서 콜론(:)으로 표시하는데 콜론과 세미콜론이 많아지면 복잡해질 염려가 있다. 이후에 설명하겠지만 Scala에서는 Nested Function도 정의할 수 있기 때문이다.

    scala> def addOne(m: Int): Int = m + 1
    addOne: (m: Int)Int

    정의한 function을 사용해보자

    scala> var three = addOne(2)
    three: Int = 3

    function은 argument가 없는 것도 정의할 수 있다. 주의해야할 것은 argument가 없는 function은 변수 명과 동일하게 취급된다. 그래서 다시 같은 이름으로 변수를 만들어 사용하게 되면 이전에 argument 없이 만든 function을 덮어 쓰게 되는 것이다.

    scala> def three() = 1+2
    three: ()Int

    scala> three
    res7: Int = 3

    scala> three()
    res8: Int = 3

    scala> var three = 1 + 3
    three: Int = 4

    scala> three
    res9: Int = 4

    scala> three()
    <console>:9: error: Int does not take parameters
                  three()
                       ^

    Anonymous Function

    Scala는 이름없이 function를 만들 수 도 있다. 이름없이 function를 만들면 인터프리터가 res{number} 라는 곳에 그 function 자체를 저장한다. Scala에서는 function 자체도 Object로 인식하기 때문에 가능하다. 그리고 function를 실행시킬때는 res{number}라는 이름을 사용해서 정의한 파라미터를 넘기면 anonymous function을 만들어서 사용할 수 있다.
    scala> (x: Int) => x + 1
    res0: Int => Int = <function1>

    scala> res0(1)
    res1: Int = 2

    function이 object라는 말을 이해하면 다음처럼 function을 변수에 넣을 수 있게 되고 그 변수를 마치 function 처럼 사용할 수 있다.

    scala> var addOne = (x: Int) => x + 1
    addOne: Int => Int = <function1>

    scala> addOne(1)
    res2: Int = 2

     위 function의 예제들은 모두 하나의 expression만 사용했는데 여러가지 expressions를 사용할 때는 {}로 묶어서 사용한다.

    scala> def timesTwo(i: Int): Int = {
         | println("hello world")
         | i * 2
         | }
    timesTwo: (i: Int)Int

    scala> timesTwo(2)
    hello world
    res3: Int = 4

    Partial Application

    이 개념도  Scala에서 처음 보는 방법인데 Rails에서 partail과 그 개념은 비슷하다. 다른 곳에서 이미 값이나 결과를 만들어서 재 사용하고 특정 값을 받는 개념이다. 아래 예제를 살펴보면 adder에서 m, n을 파라미터로 받아서 처리하는 function 을 정의해서 add2 변수에 넣을 때 부분적으로 만들었던 function에 아규먼트 중에 하나의 값을 이미 정해두고, 새로 들어오면 파라미터는 다른 아규먼트로 전달되어 처리하게 하는 방법이다.

    scala> def adder(m: Int, n: Int) = m + n
    adder: (m: Int, n: Int)Int

    scala> val add2 = adder(2, _:Int)
    add2: Int => Int = <function1>

    scala> add2(3)
    res4: Int = 5

      
    Curried Function
     

    Curried function은 Partial Application 과 비슷하게 보인다. 하지만 Curried Function을 Partial Application으로 사용하지 말라고 권고하고 있다. Curried function은 헤스켈 언어에서 나오는데 여러개의 파라미터를 받는 function은 하나의 파라미터를 받는 function 여러개를 사용해서 만들어 낼 수 있다는게 개념이다.

    scala> def multiply(m: Int)(n: Int): Int = m *n
    multiply: (m: Int)(n: Int)Int

    scala> multiply(2)(3)
    res5: Int = 6

    scala> var timeTwo = multiply(2)(_)
    timeTwo: Int => Int = <function1>

    scala> timesTwo(3)
    hello world
    res6: Int = 6

    Class

    Scala는 객체 지향 프로그래밍을 할 수 있는데 def로 메소드를 정의하고 var로 필드를 정의한다.

    scala> class Calculator {
         |    var brand: String = "HP"
         |    def add(m: Int, n: Int): Int = m + n
         | }
    defined class Calculator

    scala> var calc = new Calculator
    calc: Calculator = Calculator@43b6c732

    scala> calc.add(1,2)
    res0: Int = 3

    scala> calc.brand
    res1: String = HP

    Constructor

    생성자는 따로 초기화 메소드가 있는 것이 아니라 클래스를 정의할 때 클래스 밖에서 아규먼트를 받을 수 있게 정의하여 생성자와 같이 사용할 수 있다.

    scala> class Calculator(brand: String) {
         | var color: String = if(brand == "T1"){
         | "blue"
         | } else if (brand == "HP") {
         | "black"
         | } else {
         | "white"
         | }
         | 
         | def add(m: Int, n: Int): Int = m +n
         | }
    defined class Calculator

    scala> var cal1 = new Calculator("T1")
    cal1: Calculator = Calculator@64ba3b30

    scala> var cal2 = new Calculator("HP")
    cal2: Calculator = Calculator@42658704

    scala> cal1.color
    res3: String = blue

    scala> cal2.color
    res4: String = black

    Inheritance

    상속하는 방법은 자바에서 상속하는 방법과 동일하게 extends를 사용한다. 이 때 상위 클래의 생성자메소드를 정의한것과 동일한 생성자를 클래스를 정의할 때 사용하여 한다.

    scala> class ScientificCalculator(brand: String) extends Calculator(brand){
         | def log(m: Double, base: Double) = math.log(m) /math.log(base)
         | }
    defined class ScientificCalculator

    scala> var cal3 = new ScientificCalculator("HP")
    cal3: ScientificCalculator = ScientificCalculator@3a779f5e

    scala> cal3.color
    res5: String = black

    scala> cal3.log(3.0, 2.0)
    res6: Double = 1.5849625007211563

    scala> cal3.add(3,5)
    res7: Int = 8
     

    Overloading method

    scala의 override는 Java의 override와 비슷하게 상속받은 클래스에서 동일한 메소드 이름으로 구현하면 된다. 

    scala> class Foo { def foo: String = "Foo" }
    defined class Foo

    scala> class Bar extends Foo { 
         | override def foo : String = "Bar"
         | }
    defined class Bar

    scala> var f  = new Foo;
    f: Foo = Foo@62224002

    scala> f.foo
    res10: String = Foo

    scala> var b = new Bar
    b: Bar = Bar@1039f33

    scala> b.foo
    res11: String = Bar

    JVM은 현재까지 알려진 VM 중에서 가장 안정화되어 있다고 알려져 있다. Java의 객체 지향과 이식성, 재사용성을 가지면서도 Ruby나 Python과 같이 간결한 코드로 프로그램을 Scala로 작성할 수 있다. 간단하게 Scala를 시작하기 위해서 정리했는데 다음 포스팅에서는 Scala 언어만 가지고 있는 특징과 그 특징을 이용해서 Java 코드를 Scala로 코드로 변경하여 코드량을 줄일 수 있는 예제들을 작성할 예정이다.

    [참고자료]

    1. Twitter Scala School 

    2. @Outsideris 님께서 Scala에 대한 자료를 블로한 자료들이 공부하는데 많은 도움을 받고 있어서 공유합니다.



    저작자 표시 비영리 동일 조건 변경 허락

    의견 남기기

    소중한 의견을 남겨주세요. 연구하는데 도움이 큰 도움이 됩니다.

    facebook으로 의견 남기기

    Disqus로 의견 남기기