SW 설계/스칼라

스칼라: implicit 기본 사용법

yztech 2021. 10. 27. 04:08
반응형

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를 이해하고, 기본적으로 사용하는 방법을 알아보았습니다.

다음 시간에는 좀더 구체적인 예를 가지고, 활용하는 방법을 알아보도록 하겠습니다.

반응형