본문 바로가기
개발/SCALA

under score 정리 [펌]

by 로그인시러 2017. 3. 28.



첫 슬라이드는 다음과 같습니다. 뭔가 어려워보이죠? 각종 _ 의 용법은 모두 들어가 있습니다.
아주 간단하게 설명하면 아래의 offset 에 대입되는 커링 함수 sum2(count) 에서 count는 매번 실행시의 count 값이 바인딩됩니다.(악 벌써 여기부터 어려워!!!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Underscores {
    import collection.{ Map => _ , _ }
 
    var count : Int = _
 
    def sum = (_:Int) + (_:Int)
    def sum2(a:Int)(b:Int) = a+b
    def offset = sum2(count) _
 
    def sizeOf(l:Traversable[_]) : Unit = l match {
        case it:Iterable[Int] => count = (0/:it)(_ + _)
        case s:Seq[_] => s.foreach( _ => count = count + 1)
        case _ => println(offset(l.size))
    }
}

두번째 슬라이드는 각각 어떤 용법으로 이루어졌나를 보여줍니다. 총 6가지 용법을 색상까지 이쁘게 보여주네요.

세번째 슬라이드 부터 각각의 용법에 대해서 알려줍니다.

1번은 “모두”를 의미합니다. 아래의 예에서 첫번째 Map => _ 는 일단 무시하시고(5번이니깐요.)
그 뒤의 _ 가 자바에서의 import * 와 같은 용법입니다.(왜 *가 아닌지는…)

1
import collection.{ Map => _ , _ }

실제 예는 다음과 같습니다.

1
2
3
4
5
6
7
import java.util._
val date = new Date()
 
import scala.util.control.Breaks._
breakable {
    for (i <- 0 to 10) { if (i == 5) break }
}

웬지 breakable은 Exception을 잡아서 나가는 것 같은 느낌이 진하게 납니다.

2번은 디폴트 값 지정입니다. 숫자면 0 문자면 null로 지정됩니다.

1
var count : Int = _

다만 이렇게 지정하는 건 생성자에서만 되고 함수안에서는 되지 않습니다.

1
2
3
4
5
6
7
8
class Foo {
    var i:Int = _ // i = 0
    var s:String = _ // s = null
 
    def f {
    // var i:String = _//error: local variables must be initialized
    }
}

3번째는 unused variables 입니다. 아래와 같이 _로 받은걸 쓰지 않게 되는 겁니다.

1
case _ => println(offset(l.size))

예를 보면 다음과 같습니다. 아래의 두 예는 같은 예입니다. x를 파라매터로 받지만… 쓰지 않는 겁니다.

1
2
(1 to 5) foreach { (x:Int) => println("one more")}
(1 to 5) foreach { _ => println("one more")}

다음 예제들도 동일합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
def inPatternMatching1(s:String) {
    s match {
        case "foo" => println("foo !")
        case x => println("not foo")
    }
}
 
def inPatternMatching2(s:String) {
    s match {
        case "foo" => println("foo !")
        case _ => println("not foo")
    }
}

4번째는 이름 없는 파라매터입니다. 아주 명확하게 들어갈 변수 대신에 지정되게 됩니다.(3번하고는 반대입죠.)
아래의 예는 1…10 까지가 x로 바인딩되는데, 이걸 _로 대체하는 경우입니다. 명시적으로 사용하기 위해서이죠.

1
2
3
4
5
(1 to 10) map { x => x + 1}
(1 to 10) map { _ + 1}
 
(1 to 10).foldLeft(0) { (x,y) => x+y }
(1 to 10).foldLeft(0) { _+_ }

이제 partial function 에서 보면 더더욱 눈이 휘둥굴해 집니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
def f(i:Int) : String = i.toString
 
def g = (x:Int) => f(x)
def g2 = f _
def f2 = (_:String).toString
 
def u(i:Int)(d:Double) : String = i.toString + d.toString
 
def v = u _
 
def w1 = u(4) _
 
def w2 = u(_:Int)2.0)

5번은 아까 Map 관련 헤더들을 import 하지 말라는 뜻입니다.
6번은 c++의 Template 처럼 특정 타입을 지칭하는 것입니다. 위에서 넘어온 타입을 그대로 사용하겠다라고 하면 이해가 쉬울까요.

다시 한번 말씀드리지만, 슬라이드가 잘 되어있으니, 실제로 보시면 꽤 도움이 되실껍니다. 뭐, 저도 공부하는 중이라…


출처 : https://charsyam.wordpress.com/2015/03/03/%EC%9E%85-%EA%B0%9C%EB%B0%9C-scala%EC%9D%98-%EA%B1%B0%EC%8B%9C%EA%B8%B0-_underscore-%EC%9D%98-%EC%9A%A9%EB%B2%95-%EC%A0%95%EB%A6%AC/

'개발 > SCALA' 카테고리의 다른 글

Case class [펌]  (0) 2017.07.25
함수형 프로그래밍 [펌]  (0) 2017.04.19

댓글