관리 메뉴

HAMA 블로그

스칼라 강좌 (36) {} 익숙해지기, {} 는 어디서 사용되는가? 본문

Scala

스칼라 강좌 (36) {} 익숙해지기, {} 는 어디서 사용되는가?

[하마] 이승현 (wowlsh93@gmail.com) 2017. 2. 17. 20:32



{} 는 어디서 사용되는가?


이름 있는 함수


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

이름 없는 함수 :  {} 를 통해 묶었다. 

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

이렇게 스칼라 코드를 읽을때 개인적으로 자바와 가장 큰 차이점 중 하나는 시도 때도 없이 나타나는 {} 이다. 

def tweets = WebSocket.acceptWithActor[String, JsValue]{ request => out =>
TwitterStreamer.props(out)
}

예를들어 여기서 { } 는 뭘까? 

object Test {
type HandlerProps = String => String
def apply(f : String => HandlerProps): Unit = {
val g = f("HELLO")
log(g("world"))
}
}


object FuturesDataType extends App {
Test{
x => y => x + y
}

}

여기 Test 에서 { } 는 뭐냔 말이다. 여기서는 apply 가 생략되고 매개변수로 { } 사이의 값이 들어간다. 

스칼라에서는 즉 { } 가 () 랑 같이 사용되기도 한다.



val l = List(1, 2, 3)
val m = l.map({_.toString})

여기서 부터 냄새가 좀 날 것이다.  ㅇㅋ 위의 map 에서 ( ) 를 생략 할 수 있다.  그렇다 스칼라는 생략 할 수 있을거 같은 것들은 죄다 생략 가능하게 만들어 놨다;;;  아래와 같이 작성 가능하다.


val m = l map{_.toString}

점도 생략했고 (대신 빈칸을 넣음) 괄호 () 를 생략했다.


val m = l.map(_.toString)

근데 이렇게도 된다.  () 랑 {} curly braces 랑 둘다 되네?  


val lst = Seq(1,2,3,4,5)
lst foreach {x => println(s"you get the idea, $x")}
lst foreach (x => println(s"you get the idea, $x"))

이렇게도 되고~

val a =  List(1, 2, 3).reduceLeft{_ + _} // 6

val b = List(1, 2, 3).reduceLeft(_ + _) // 6

이렇게도 된다.


하지만 패턴매칭의 경우에는 

val map = Map("foo" -> "bar")
map foreach { case (k, v) => println(s"key: $k, value: $v") }

이건 좋습니다요~

map foreach ( case (k, v) => println(s"key: $k, value: $v") )

하지만 패턴매칭에서는 {} 빼면 에러이다.


for comprehension 문에서도 {} 는 필수이다.

val res = for {
x <- coll1
y <- coll2
} yield (x, y)



이제 알짜배기가 나온다. 잘 보시라~

스칼라에서는 함수호출시  ()  대신 {} 중괄호를 사용 할 수 있다.  단 !!! 인재가 하나일 경우 !!

println ("Hello World") 대신해서 println { "Hello World" } 를 사용 할 수 있다는 의미이다.


스칼라에서 이렇게 한 이유는 클라이언트 프로그래머가 중괄호 내부에 함수 리터럴을 사용하도록 하기 위해서이다. 이렇게 작성한 메소드는 호출 시 좀 더 제어 추상화 구문과 비슷해진다.


def withPrintWriter(file: File, op: PrintWriter => Unit ) {

......
}


이런 함수를 호출 할 때는 

withPrintWriter ( new File ("date.txt") , 

writer => writer.println(new java.util.Date) ) 


이렇게 할 수 있는데 , 인자가 2개이기 때문에 { } 를 사용할 수 없다.


하지만 !!!!


def withPrintWriter(file: File) (op: PrintWriter => Unit ) {

...
}


이러한 함수라면 {} 를 사용가능하다.

val file = new File("date.txt")
withPrintWriter (file) {
writer => writer.println(new java.util.Date)
}



왜 그러냐면 커링을 통해서 file 을 매개변수로 먼저 넣은 새로운 함수가 생겨졌고, 

그 새로운 함수는  매개변수 하나를 필요로 하는 함수이기 때문이다.




이런것들이 온갖 문법에 스며들어 있기 때문에 편하게 스칼라를 사용하기 위해서는 처음엔 고생 좀 해야한다.

Comments