익명 함수

익명 함수 (Anonymous Functions)

익명 함수(anonymous function) — 람다(lambda) 라고도 부르죠 — 는 고차 함수(higher-order function)에 인자로 전달되는 코드 블록이에요. 위키백과에서는 익명 함수를 “식별자에 묶이지 않은 함수 정의”라고 정의해요.

출처: Scala 3 Book — Anonymous Functions

예를 들어 이런 리스트가 있다고 할게요.

val ints = List(1, 2, 3)

List 클래스의 map 메서드와 여러분만의 커스텀 익명 함수를 사용하면, ints의 각 요소를 2배로 만든 새 리스트를 만들 수 있어요.

val doubledInts = ints.map(_ * 2)   // List(2, 4, 6)

주석에서 보이듯이 doubledIntsList(2, 4, 6)이라는 리스트를 담아요. 이 예시에서 코드의 이 부분이 익명 함수랍니다.

_ * 2

이건 “주어진 요소를 2로 곱하라”는 뜻을 짧게 표현한 거예요.

더 긴 형태 (Longer forms)

Scala에 익숙해지면 함수 안의 한 지점에서 변수 하나를 쓰는 익명 함수를 쓸 때 저 형태를 항상 쓰게 될 거예요. 하지만 원한다면 더 긴 형태로도 쓸 수 있어요. 그래서 이런 코드를 쓰는 것 말고도

val doubledInts = ints.map(_ * 2)

이런 형태들로도 똑같이 표현할 수 있어요.

val doubledInts = ints.map((i: Int) => i * 2)
val doubledInts = ints.map((i) => i * 2)
val doubledInts = ints.map(i => i * 2)

이 줄들은 전부 완전히 같은 뜻이에요. ints의 각 요소를 2배로 만들어 새 리스트 doubledInts를 만든다는 거죠. (각 형태의 문법은 잠시 후에 설명할게요.)

Java에 익숙하다면, 이 map 예시들이 다음 Java 코드와 같다는 걸 알아두면 도움이 될 거예요.

List<Integer> ints = List.of(1, 2, 3);
List<Integer> doubledInts = ints.stream()
                                .map(i -> i * 2)
                                .collect(Collectors.toList());

익명 함수 줄이기 (Shortening anonymous functions)

명시적으로 쓰고 싶다면, 익명 함수를 이런 긴 형태로 작성할 수 있어요.

val doubledInts = ints.map((i: Int) => i * 2)

그 표현식 안의 익명 함수는 바로 이것이에요.

(i: Int) => i * 2

이 문법에 익숙하지 않다면 => 기호를 변환기(transformer)로 생각하면 도움이 돼요. 그 표현식이 기호 왼쪽의 파라미터 리스트(i라는 Int 변수)를 기호 오른쪽의 알고리즘(이 경우엔 Int를 2배로 만드는 표현식)을 사용해 새로운 결과로 변환 하니까요.

그 표현식 줄이기 (Shortening that expression)

이 긴 형태는 다음 단계를 거쳐 줄일 수 있어요. 먼저 가장 길고 가장 명시적인 형태부터 다시 볼게요.

val doubledInts = ints.map((i: Int) => i * 2)

Scala 컴파일러가 ints 안의 데이터로부터 iInt임을 추론할 수 있기 때문에, Int 선언은 제거할 수 있어요.

val doubledInts = ints.map((i) => i * 2)

인자가 하나뿐이므로 파라미터 i를 감싸는 괄호도 필요 없어요.

val doubledInts = ints.map(i => i * 2)

Scala에서는 함수 안에 파라미터가 한 번만 등장할 때 변수 이름 대신 _ 기호를 쓸 수 있기 때문에, 코드를 더 단순하게 만들 수 있어요.

val doubledInts = ints.map(_ * 2)

더 짧게 (Going even shorter)

다른 예시에서는 익명 함수를 더 단순화할 수도 있어요. 예를 들어 가장 명시적인 형태에서 시작해서, List 클래스의 foreach 메서드와 함께 이 익명 함수를 사용해 ints의 각 요소를 출력할 수 있어요.

ints.foreach((i: Int) => println(i))

이전과 마찬가지로 Int 선언은 필요 없고, 인자가 하나뿐이므로 i 주변의 괄호도 필요 없어요.

ints.foreach(i => println(i))

i가 함수 본문에서 한 번만 사용되므로, _ 기호로 표현식을 더 단순화할 수 있어요.

ints.foreach(println(_))

마지막으로, 익명 함수가 인자 하나를 받는 메서드 호출 하나로 이뤄져 있다면, 인자를 굳이 이름 붙여 명시할 필요가 없어요. 그래서 마침내 메서드 이름(여기서는 println)만 쓰면 됩니다.

ints.foreach(println)

더 알아보기 (Learn more)