303
6
장
스칼라 함수형 프로그래밍
scala
>
val states3
=
states2
+
("
New York
",
"
Illinois
")
states3
:
scala
.
collection
.
immutable
.
Set
[
String
]
=
Set
(
Alaska
,
Virginia
,
Alabama
,
New York
,
Illinois
,
Wyoming
)
Map
과 마찬가지로
scala
.
collection
.
Set
(
http
://
bit
.
ly
/
1tprGN8
) 트레이트는 오직 변경
불가능한 연산만 정의한다. 변경 불가능한 집합과 변경 가능한 집합에 대한 파생 트레이트인
scala
.
collection
.
immutable
.
Set
(
http
://
bit
.
ly
/
1u1fTHy
)과
scala
.
collection
.
mutable
.
Set
(
http
://
bit
.
ly
/
1wl5arf
)이 존재한다. 여러분은 변경 가능한 버전을 명시적으로 임포트해
야 하지만, 변경 불가능한 버전이 이미
Predef
에 의해 노출되어 있다. 두 구현 모두 원소를 추
가하고 삭제하는
+
와
-
연산, 반복자인
Iterator
(다른 집합, 리스트 등이 이런 반복자가 될 수
있다 )에 정의된 원소들을 추가하고 삭제하는
++
와
--
연산을 제공한다.
6.8
순회하기, 연관시키기, 걸러내기, 접기, 축약하기
일반적인 함수 컬렉션 (시퀀스, 리스트, 맵, 집합, 그리고 배열, 트리 등 )은 모두 읽기 전용 순회
를 기반으로 하는 여러 가지 공통 연산을 지원한다. 실제로 여러분이 다른 ‘컨테이너
container
’ 타
입을 구현할 때도 이런 연산을 지원하게 만들면 이런 균일성을 누릴 수 있다. 예를 들어
Option
은 원소가 없거나 하나 있는 컨테이너로,
None
과
Some
이 그 두 경우를 표현한다.
6.8.1
순회
스칼라 컨테이너의 표준적인 순회 메서드는
foreach
다. 이는
scala
.
collection
.
IterableLike
(
http
://
bit
.
ly
/
1E8xVd5
)에 정의되어 있으며, 다음과 같은 시그니처를 가진다.
trait IterableLike
[
A
]
{
//
일부
자세한
부분
생략함
...
def foreach
[
U
](
f
:
A
=
>
U
):
Unit
=
{...}
...
}
304
2
부
기본기 다지기
IterableLike
의 일부 서브클래스는 더 나은 성능을 얻기 위해 자기 자신에 대한 세부 지식을
활용하는 데 이 메서드를 오버라이딩할 수 있다.
함수의 반환 타입인
U
가 어떤 타입인지는 중요치 않다.
foreach
의 출력은
Unit
이며, 그렇기
때문에 완전히 부수 효과만을 위한 함수다. 함수를 인자로 받기 때문에
foreach
도 여기서 설명
할 다른 연산과 마찬가지로 고차 함수다.
foreach
는 원소 개수에 대해
O
(
N
)의 복잡도를 가진다. 다음은 리스트와 맵에서 이를 사용한
예다.
//
code
-
examples
/
progscala2
/
fp
/
datastructs
/
foreach
.
sc
scala
>
List
(
1
,
2
,
3
,
4
,
5
)
foreach
{
i
=
>
println
("
Int
:
"
+
i
)
}
Int
:
1
Int
:
2
Int
:
3
Int
:
4
Int
:
5
scala
>
val stateCapitals
=
Map
(
|
"
Alabama
"
-
>
"
Montgomery
",
|
"
Alaska
"
-
>
"
Juneau
",
|
"
Wyoming
"
-
>
"
Cheyenne
")
stateCapitals
:
scala
.
collection
.
immutable
.
Map
[
String
,
String
]
=
Map
(
Alabama
-
>
Montgomery
,
Alaska
-
>
Juneau
,
Wyoming
-
>
Cheyenne
)
//
stateCapitals foreach
{
kv
=
>
println
(
kv
.
_
1
+
":
"
+
kv
.
_
2
)
}
scala
>
stateCapitals foreach
{
case
(
k
,
v
)
=
>
println
(
k
+
":
"
+
v
)
}
Alabama
:
Montgomery
Alaska
:
Juneau
Wyoming
:
Cheyenne
Map
예제의 경우,
foreach
에 넘겨진 함수의 인자의
A
타입이 실제로는 키와 값의 쌍인
(
K
,
V
)
라는 것에 유의하라. 키와 값을 뽑아내기 위해 패턴 매치 식을 사용할 수 있다. 튜플을 사용한
같은 의미의 구문을 주석에 표시해두었다.
2
2
주_
case
절로시작한익명함수는실제로는
PartialFunction
을정의한다.하지만이경우모든입력과일치하기때문에실제로는
완전함수(
total
function
)다.
305
6
장
스칼라 함수형 프로그래밍
foreach
는 부수 효과만 수행할 수 있기 때문에 순수 함수가 아니다. 하지만 일단
foreach
만
있으면 다음부터 설명할 모든 다른 순수 연산을
foreach
를 사용해서 구현할 수 있다. 이런 연
산은 함수형 프로그래밍의 특징이며, 연관시키기
mapping
, 걸러내기
filtering
, 접기
folding
, 축약시키
기
reducing
등으로 구분할 수 있다.
6.8.2
연관시키기
map
메서드에 대해서는 이미 살펴봤다.
map
은 원래 컬렉션과 같은 크기의 새로운 컬렉션을 반
환하며, 새 컬렉션의 각 원소는 원래 컬렉션의 원소에 함수를 적용해서 변환한 결과다.
map
은
scala
.
collection
.
TraversableLike
(
http
://
bit
.
ly
/
1yMk4pK
)에 정의가 들어 있고, 대부
분의 컬렉션은 이를 상속한다. 시그니처는 다음과 같다.
trait TraversableLike
[
A
]
{
//
일부
자세한
부분
생략
...
def map
[
B
](
f
:
(
A
)
⇒
B
):
Traversable
[
B
]
...
}
이번 장 앞부분에서
map
에 대한 예제를 이미 봤다.
방금 본
map
메서드의 시그니처는 실제 소스 코드에 있는 시그니처와는 다르다. 실제로는 스칼
라독 (
http
://
bit
.
ly
/
1yMk4pK
)이 표시해주는 시그니처다. 스칼라독 항목을 보면, 맨 마지막에
‘전체 시그니처’ 부분을 볼 수 있고, 그 옆에 있는 화살표를 클릭해서 펼칠 수 있다. 그러면 다음
과 같은 실제 시그니처를 볼 수 있다.
def map[B, That](f: A =
>
B)(implicit bf: CanBuildFrom[Repr, B, That]): That
최근의 스칼라독은 몇몇 메서드에 대해 단순화한 시그니처를 보여준다. 이는 독자들이 자세한
구현 사항으로 인해 당황하지 않도록, 메서드의 ‘핵심’만 전달하기 위해서다.
map
메서드의 핵심
은 한 컬렉션을 같은 종류와 크기의 새 컬렉션으로 변환하는 것이다.
A
는 원래 컬렉션의 원소 타
입이고,
B
는 함수의 반환 타입으로, 결과 컬렉션의 원소 타입이 된다.
Get 프로그래밍 스칼라: 실용적인 스칼라 활용법을 익히는 가장 확실한 실전 바이블 (2.11.x 버전 기반) now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.