implicit는 boilerplate 코드를 줄여서, 코드의 가독성을 높이는데 자주 사용됩니다. Boilerplate 코드란 별 수정 없이 많은 곳에서 반복적으로 사용되는 코드를 의미합니다. Scala에서는 이러한 코드들을 implicit 키워드를 사용하여 생략하고 코드를 줄여줍니다. 사전적 의미로 implicit 는 암시적인이란 뜻이므로, 구체적으로 명시하지 않고 사용한다는 것을 의미합니다. 보통 자동 형 변환이나 늘 사용하는 인자를 전달하는 용도로 사용됩니다.
장점은 함수들에서 자주 사용되는 인자들을 implicit로 선언하면, 생략할 수 있지만,
단점은 문법이 복잡해져, 숙달되지 않은 사람들에게는 어렵게 느끼질 수 도 있습니다.
간단하게는, 인자에 implicit 가 있으면, 늘 사용되므로 미리 생성해 놓았다고 생각하면 이해하는데 도움이 될 수도 있습니다.
예 1. 자동 형 변환
자동 형변환 (type casting) 의 예를 한 가지 보도록 하겠습니다.
scala> implicit def doubleToInt(d: Double) = d.toInt
doubleToInt: (d: Double)Int
scala> val a: Int = 12.3
a: Int = 12
위 코드에서 자동으로 형변환이 이루어집니다.
(1)에서 Double형을 받아서 Int형을 반환하는 함수를 implicit로 정의했습니다.
(4)에서 Int형 변수 a에 Double 형 값 12.3을 설정할 경우, 컴파일러는 Double형을 받아서, Int형을 반환하는 implicit 함수를 찾게 되고, (1)에서 doubleToInt 함수가 implicit 형 함수로 선언되어 있으므로, 이를 사용하여 Double 값을 Int 값으로 변환해서 a 에 넣게 됩니다.
위 코드는 명시적으로 doubleToInt 이름의 함수를 선언 후, 이 함수를 직접 호출해서 사용하는 다음 코드와 같습니다.
scala> def doubleToInt(d: Double) = d.toInt
doubleToInt: (d: Double)Int
scala> val a: Int = doubleToInt(12.3)
a: Int = 12
컴파일러는 단지 Double 형을 받아서 Int 형을 반환하는 implicit 로 선언된 함수만을 찾게 됩니다. 이 말은 실제 함수가 어떻게 구현되었는지 상관없다는 것으로, 아래 코드를 보면, 쉽게 이해할 수 있습니다.
scala> implicit def doubleToInt(d: Double) = d.toInt + 1
doubleToInt: (d: Double)Int
scala> val a: Int = 12.3
a: Int = 13
따라서, 자주 사용되는 형 변환 같은 함수들을 implicit 로 선언하면, 명시적 형 변환 없이도 자동 형 변환이 가능해서 코드를 단순화시키고, 가독성을 높일 수 있습니다.
예 2. 늘 사용하는 인자의 전달
두번째 예로, 늘 사용하는 인자를 implicit 변수를 사용해서 인자 없이 함수를 호출하는 코드를 구현해보겠습니다.
scala> def pow2(implicit x: Int) = x * x
pow2: (implicit x: Int)Int
scala> pow2
<console>:14: error: could not find implicit value for parameter x: Int
pow2
^
scala> val x=4
x: Int = 4
scala> pow2
<console>:14: error: could not find implicit value for parameter x: Int
pow2
^
scala> implicit val a = 4
a: Int = 4
scala> pow2
res2: Int = 16
위 예 (1)에서 pow2 함수에 전달되는 인자 x 를 implicit 형으로 선언했습니다.
(4)에서 pow2 함수를 호출하면, 인자 x 에 대한 implicit 형 값이 없다고 오류가 발생합니다.
컴파일러는 위 함수를 호출할 때, 인자가 implicit 형으로 선언되면, implicit 형으로 선언된 변수들을 찾게 되고, 해당 변수의 이름이나 값은 상관없이 implicit 형 선언 여부를 확인합니다.
(9) Int 형 변수 x를 선언해도 implicit 형 변수가 아니므로, (12)에서 함수 호출 시 여전히 동일한 오류가 발생합니다. 하지만, (17) 에서 implicit 형 변수를 선언하게 되면, (20)에서는 pow2 호출시 implicit 로 선언된 값 4는 implicit 형으로 선언된 인자 x 에 전달되어, 16을 오류 없이 반환하게 됩니다.
정리하면, (1)에서 implicit 형 인자를 받는 함수 pow2를 선언하고, (20)에서 이 함수를 인자 없이 호출해도 오류 없이 결과가 반환됩니다. 단, 호출하기 전에 (17)에서 implicit형 인자가 선언되어 있어야 합니다. 따라서, 어떤 함수에서 implicit 형 인자가 사용되었다면, 이 인자에 전달될 값은 어딘가에 implicit형으로 이미 선언되어 있다고 생각하면 편리합니다.
주의 사항
implicit 형 인자를 사용할 때 함수 선언시 사용 가능한 경우에 제한이 있습니다.
scala> def pow2(implicit x: Int) = x * x
pow2: (implicit x: Int)Int
scala> def add1(implicit x: Int, y: Int) = x + y
add: (implicit x: Int, implicit y: Int)Int
scala> def add2(x: Int, implicit y: Int) = x + y
<console>:1: error: identifier expected but 'implicit' found.
def add2(x: Int, implicit y: Int) = x + y
^
scala> def add3(x: Int)(implicit y: Int) = x + y
add2: (x: Int)(implicit y: Int)Int
scala> def add4(implicit x: Int)(y: Int) = x + y
<console>:1: error: '=' expected but '(' found.
def add3(implicit x: Int)(y: Int) = x + y
^
scala> def add5(implicit x: Int)(implicit y: Int) = x + y
<console>:1: error: '=' expected but '(' found.
def add3(implicit x: Int)(implicit y: Int) = x + y
pow2 는 단일 인자를 implicit 형으로 받는 함수이고, 나머지 함수들은 2개의 인자를 받는 함수들입니다.
(1)에서 pow2 의 인자를 implicit로 선언하고 있습니다.
(4)에서 add1 의 경우 앞의 인자에 implicit 를 선언하면, 컴파일러는 두 인자 모두 implicit 형으로 받아들입니다.
하지만, (7)에서 add2 의 경우 뒤의 인자에 implicit 를 선언하면, 컴파일러는 뒤에는 implicit 형을 쓸 수 없다고 오류를 발생시킵니다.
(11)에서 add3 의 경우, 두 인자를 나눠서 curried 함수로 선언하면, 컴파일러는 뒤의 인자만 implicit 형으로 받아들일 수 있습니다.
(14)에서 add4 의 경우, 두 인자를 나눠서 curried 함수로 선언했지만, 컴파일러는 앞에 선언한 implicit 형 인자는 오류를 발생시키고,
(19)에서도 curried 함수에서의 두 인자 모두 implicit로 선언해도, 역시 오류를 발생시킵니다.
따라서, 모든 인자가 implicit 형인 경우에는 (4)와 같이 선언해야 하고,
일부 인자만 implicit 형 인경우에는 (11)과 같이 curried 함수로 나눠서 선언하고, implicit형 인자는 뒤에 선언합니다.
지금까지 스칼라에서 implicit를 이해하고, 기본적으로 사용하는 방법을 알아보았습니다.
다음 시간에는 좀더 구체적인 예를 가지고, 활용하는 방법을 알아보도록 하겠습니다.
'SW 설계 > 스칼라' 카테고리의 다른 글
| 스칼라: implicit 사용법 응용 (0) | 2021.10.27 |
|---|---|
| 스칼라: Mixins (0) | 2021.10.09 |
| 스칼라: Sealed, Final, Option, Try 클래스 (0) | 2021.09.25 |
| 스칼라: 부분적용함수 (Partially Applied Function), 부분함수 (Partial Function) 그리고 Case (0) | 2021.09.25 |