Scala에서 Underscore(_)의 자주 사용하게 된다. _ (Placeholder)라는 표현을 쓰는 것 같은데 맞는지 모르겠다. 이하는 내용에서는 Underscore(_)이라고 일반화해서 이야기하겠다. 용도는 “그때그때 달라요!”다. 쓰이는 곳에 따라 완전히 다른 의미를 가진다.

다양한 쓰임새 중에 본인이 알고 있는 수준에서 정리해보았다.

Package Import

특정 패키지의 이하 모든 요소를 import 할 때 사용하다.

1
import scala.collection._

반대로 패키지 중에 특정 요소를 제외할 때도 사용된다.

1
2
3
4
5
import java.util.{Date=>_, _}
// Date=>_는 제거, _ 나머지 모두 삽입
...
val arrayList = new ArrayList[String]()
val date = new Date() //error

기본값으로 초기화

Scala에서 추상화 클래스나 트레잇이 아니면 초기화 안된 변수를 가질 수 없다. 반대로 초기화를 항상 해야 한다. 그래서 Underscore를 기본값 초기화용으로 사용하나 보다.

1
2
3
4
5
6
7
8
@ var i : Int = _
i: Int = 0

@ var s : String = _
s: String = null

@ var d : Double = _
d: Double = 0.0

변수 선언 시 초기화 좌변에 Underscore가 오면 해당 변수 타입의 기본값으로 초기화가 이루어진다.

Match문 catch all

Scala의 매칭 구문은 강력하다. 여기서도 Underscore가 쓰인다.

1
2
3
4
5
6
def whoareyou (s:String) {
s match {
case "walker" => println("developer.")
case _ => println("unknown people.")
}
}

case _는 매칭 조건에 맞지 않는 모든 항목들이 매칭된다.

Property Setter

Scala라는 클래스 멤버 변수값에 접근하기위해서 Property 필요하다. 선언하지도 않고 변수명이랑 동일해서 바로 변수에 전 근하는 것 같지만. 기본적으로 멤버 변수에 대해서 Getter/Setter가 자동으로 생성된다. 개발자가 직접 Setter를 정의할때 Underscore 쓰인다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

@ class Test {
var n:Int = 0;
def n_=(s:String):Unit = n = s.toInt * 100
}
defined class Test

@ val test = new Test
test: Test = ammonite.$sess.cmd26$Test@6b6939e1

@ test.n
res28: Int = 0


@ test.n
res31: Int = 1000

예제 코드에 def n_=(s:String):Unit 가 Setter 메쏘드다. 재미있는 부분이 메쏘드명이 <멤버 변수명>_= 이라는 것이다.

의미 없는 값/변수명 무시.

해당 파라미터 변수를 내부 로직에서 사용하지 않아 변수명 자체가 의미 없을 경우 쓰인다.

1
2
3
4
5
6
7
8
9
@ val _ = 10
`_`: Int = 10

@ (1 to 5) foreach { _ => println("test")}
test
test
test
test
test

람다 고차함수 파라미터 생략

고위함수에서 변수명이 필요 없이 바로 추론할 수 있는 경우에 파라미터를 생략하고 함수 몸체만 기술하고 _로 파라미터명를 대신 사용.

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) { _ + _ }

Higher kinded type parameters

F-바운드에서 타입인자를 자기자신으로 가져갈때 생략하는 것 같은데 아직 잘 모르겠다.

1
class A[K[_],T](a: K[T])

에타확장 : eta

메쏘드는 일급함수가 아니기때문에 인자로 넘길 수가 없다. 하지만 인자가 메쏘드일 경우 자동으로 함수로 변경해준다. 이를 에타확장이라고 한다.

1
2
@ val forceFunc = test1.meth _
forceFunc: () => String = <function0>