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 |