암시를 사용하면 준비코드를 줄이고 기조 ㄴ타입에 새로운 메서드를 추가한 것과 같은 효과를 낼수있다

그리고 도메인 특화언어(DSL)의 생성을 지원할 수 있다.

그러나 암시라는 기능은 논란의 대상이 되고 있는데 그 이유는 암시를 찾을 때 소스 코드에서 지역적이 아닌 부분까지 고려하기 때문이다.

→ 가령 컴파일러가 범위안에 들어온 암시를 호출해서 메서드에 인자를 제공하거나 인자중 일부를 원하는 타입으로 변환하는 등의 기능을 제공하지만, 소스 코드를 읽을 때 어떤 암시적 값이나 메서드를 활용하고 있는지 알아보기 힘들기 때문이다.

5.1 암시적 인자

메소드의 파라미터에 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하고