221
5
장
암시
한다. 이는
Ordering
[
B
]
의 인스턴스를 취하는 암시적인
2
번째 인자 목록이 있음을 의미한다.
하지만 이 메서드 안에서
Ordering
인스턴스에 접근할 필요가 있다. 그러나 소스 코드에서 명
시적으로 이를 선언하지는 않으므로, 더 이상 그 인스턴스에 이름을 붙일 필요는 없다. 바로
Predef
.
implicitly
가 그런 일을 해준다. 메서드에 암시적으로 넘겨진 인스턴스는
implicitly
에 의해 암시적으로 처리된다. 다만 여기서는 타입 시그니처에
Ordering
[
B
]
가 필요함에 유의
하라.
NOTE
_
맥락 바운드와
implicitly
메서드를 결합한 것은 매개변수화한 타입의 암시적 인자가 필요한 특
별한 경우를 짧게 쓸 수 있는 방식이다. 여기서 타입 매개변수는 범위 안에 있는 다른 타입 중 하나여야 한다
(예를 들면 암시적
Ordering
[
B
] 타입 매개변수에 대해 [
B
:
Ordering
]).
5.2
암시적 인자를 사용하는 시나리오
암시를 현명하게 사용하고, 자주 사용하지 않는 것이 중요하다. 암시를 과도하게 사용하면 코드
를 읽는 사람이 코드가 실제로 하는 일을 이해하기 어려울 수 있다.
이런 단점이 있음에도 불구하고 왜 암시적 인자를 사용해야 하는 걸까? 암시적 인자를 사용하는
몇 가지 관용구가 있는데, 이들이 주는 이익은 크게 두 가지 범주로 나눌 수 있다. 첫째 범주는
준비를 위한 코드를 없애는 것이다. 예를 들어 맥락 정보를 명시적으로 제공하는 대신 암시적
으로 제공할 수 있다. 둘째 범주는 매개변수화한 타입을 받는 메서드에 사용해서 버그를 줄이
거나 허용되는 타입을 제한하기 위한 제약 사항으로 사용하는 것이다.
5.2.1
실행 맥락 제공하기
2
.
5
.
3
절 ‘
Future
맛보기’의 퓨처 예제에서
Future
.
apply
(
http
://
bit
.
ly
/
1pbjSQR
) 메서드의
두 번째 암시적 인자 목록에 암시적
ExecutionContext
(
http
://
bit
.
ly
/
1s0FtqF
)를 넘겼다.
apply[T](body: =
>
T)(implicit executor: ExecutionContext): Future[T]
222
2
부
기본기 다지기
몇몇 다른 메서드도 이런 식으로 암시적 인자를 받는다.
이런 메서드를 호출할 때 우리는
ExecutionContext
를 명시하지 않는 대신 컴파일러가 사용할
전역 기본 맥락을 임포트했다.
import scala.concurrent.ExecutionContext.Implicits.global
‘실행 맥락’을 넘길 때는 암시적 인자를 사용하는 것을 권장한다. 이런 맥락의 다른 예로는 실행
원자성을 보장하는 일련의 연산 묶음인 트랜젝션
transaction
, 데이터베이스 연결, 스레드 풀
thread
pool
, 사용자 세션
user
session
등이 있다. 메서드 인자를 사용하면 동작을 조합할 수 있다. 이때 그
인자를 암시적으로 만들면 사용자에게 더 깔끔한
API
를 제공할 수 있다.
5.2.2
사용 가능한 기능 제어하기
맥락을 넘기는 것 외에, 암시적 인자를 통해서 사용 가능한 기능을 제어할 수도 있다.
예를 들어 권한 토큰이 들어 있는 암시적 사용자 세션 인자를 사용해서 특정
API
연산을 사용자
가 호출할 수 있는지 판단하거나, 데이터의 가시성을 제한할 수 있다.
사용자 인터페이스의 메뉴를 만드는데, 일부 메뉴는 사용자가 로그인한 경우에만 보여야 하며,
일부는 로그인하지 않은 경우에만 보여야 한다고 가정하자. 다음과 같이 암시적 세션을 활용해
서 이를 검사할 수 있다.
def createMenu
(
implicit session
:
Session
):
Menu
=
{
val defaultItems
=
List
(
helpItem
,
searchItem
)
val accountItems
=
if
(
session
.
loggedin
())
List
(
viewAccountItem
,
editAccountItem
)
else List
(
loginItem
)
Menu
(
defaultItems
++
accountItems
)
}
223
5
장
암시
5.2.3
사용 가능한 인스턴스 제한하기
매개변수화한 타입이 있는 메서드가 있고, 그 메서드의 타입 매개변수에 사용할 수 있는 타입
을 제한하고 싶다고 가정하자.
우리가 허용하고 싶은 타입이 특정 공통 슈퍼타입의 모든 서브타입이라면 객체지향적 기법을
사용해서 암시를 피할 수 있다. 그런 기법을 먼저 고려해보자.
3
.
10
절 ‘이름에 의한 호출과 값에 의한 호출’에서 자원 관리자를 만들면서 그런 예를 살펴봤다.
object manage
{
def apply
[
R
<
:
{
def close
():
Unit
},
T
](
resource
:
=
>
R
)(
f
:
R
=
>
T
)
=
{...}
...
}
타입 매개변수
R
은
close
( ):
Unit
메서드가 있는 어떤 타입의 서브타입이어야 한다. 또는 대
상 자원이 모두
Closable
트레이트를 구현하고 있다고 가정할 수도 있다 (트레이트가 자바 인터
페이스를 대신하고 확장한다는 사실을 기억하라.
3
.
14
절 ‘트레이트: 스칼라 인터페이스와 혼합’
을 보라 ).
trait Closable
{
def close
():
Unit
}
...
object manage
{
def apply
[
R
<
:
Closable
,
T
](
resource
:
=
>
R
)(
f
:
R
=
>
T
)
=
{...}
...
}
이런 기법은 공통 슈퍼클래스가 없으면 사용할 수 없다. 그런 경우 암시적 인자를 사용해서 허
용되는 타입을 제한할 수 있다. 스칼라 컬렉션
API
는 설계 문제를 해결하기 위해 그런 방법을
사용한다.
구체적 컬렉션 클래스가 지원하는 메서드 중 상당수는 부모 타입에서 구현된다. 예를 들어
L
ist
[
A
].
map
(
f
:
A
=
>
B
):
List
[
B
]
는 각 원소에 대해
f
를 적용한 새로운 리스트를 만든다. 대
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.