암시를 사용하면 준비코드를 줄이고 기조 ㄴ타입에 새로운 메서드를 추가한 것과 같은 효과를 낼수있다
그리고 도메인 특화언어(DSL)의 생성을 지원할 수 있다.
그러나 암시라는 기능은 논란의 대상이 되고 있는데 그 이유는 암시를 찾을 때 소스 코드에서 지역적이 아닌 부분까지 고려하기 때문이다.
→ 가령 컴파일러가 범위안에 들어온 암시를 호출해서 메서드에 인자를 제공하거나 인자중 일부를 원하는 타입으로 변환하는 등의 기능을 제공하지만, 소스 코드를 읽을 때 어떤 암시적 값이나 메서드를 활용하고 있는지 알아보기 힘들기 때문이다.
메소드의 파라미터에 implicit라는 키워드를 사용한다.
→ 메서드 인자 중 사용자가 명시적으로 제공할 필요가 없는 인자를 표시하기 위해
만약 암시적 인사를 생략하는 경우, (암시적 인사를 생략하여, 원래는 암시적 인자로 사용하려했던) 그 문장을 둘러싸는 범위에서는 타입이 호환되는 값을 제공해야한다.
def calcTax(amount: Float)(implicit rate: Float): Float = amount * rate
implicit val currentTaxRate = 0.08F
val tax = calcTax(50000F)
println(tax)
// 출력값
4000.0
위의 메서드는 지역 범위에 있는 암시적 값을 사용한다.
즉 currentTaxRate라는 암시값 선언하고, 특정 메서드의 인자에 암시적인자를 표시한경우,
메서드의 인자는 선언한 암시값의 타입과 호환되도록 타입을 선언해야 하며,
따라서 val tax처럼 두번째 인자를 명시하지 않아도 위에서 선언한 암시값을 쓰게 되는 것이다.
<aside> 💡 1) 마지막 파라미터에만 implicit 키워드를 쓸 수 있다. 2) 파라미터 목록 가장 처음에만, 단 한번만 사용할 수 있다. 3) 파라미터가 implicit 키워드로 시작하면, 그 파라미터 목록안의 모든 파라미터는 implicit 키워드의 영향을 받는다
</aside>
def calcTax(amount: Float)(implicit rate: Float): Float = amount * rate
object SimpleStateSalesTax {
implicit val rate: Float = 0.05F
}
//요기까지가 어떻게 보면 위에서 말한 암시적 인자를 사용한 예시
case class ComplicatedSalesTaxData(
baseRate: Float,
isTaxHoliday: Boolean,
storeId: Int)
object ComplicatedSalesTax {
private def extraTaxRateForStore(id: Int): Float = {
0.0F
}
implicit def rate(implicit cstd: ComplicatedSalesTaxData): Float =
if (cstd.isTaxHoliday) 0.0F
else cstd.baseRate + extraTaxRateForStore(cstd.storeId)
}
{
import SimpleStateSalesTax.rate
val amount = 100F
println(s"Tax on $amount = ${calcTax(amount)}") // Tax on 100.0 = 5.0
}
///이 부분이 중요
{
import ComplicatedSalesTax.rate
implicit val myStore = ComplicatedSalesTaxData(0.06F, false, 1010)
val amount = 100F
println(s"Tax on $amount = ${calcTax(amount)}") // Tax on 100.0 = 6.0
}
///
위처럼 암시적 메서드를 사용하는 경우에는 인자도 암시적으로 만들어야 한다.
ComplicatedSalesTax object의 암시적 메서드인 rate를 import하고