컴파일러가 암시적 값을 찾지 못할 때 원인을 진단하고 해결하는 방법을 안내합니다.

소요 시간: 약 10-15분

TL;DR
  • Scala 2: -Xlog-implicits 플래그로 검색 과정 확인
  • Scala 3: 컴파일러 메시지가 더 명확하며, import 제안도 제공
  • 공통: 스코프에 암시적 값이 있는지, 타입이 정확히 일치하는지 확인

이 가이드가 해결하는 문제#

다음과 같은 컴파일 에러가 발생할 때 이 가이드를 사용하세요:

could not find implicit value for parameter ord: Ordering[MyClass]

또는

ambiguous implicit values
No given instance of type Ordering[MyClass] was found

또는

Ambiguous given instances

이 가이드가 다루지 않는 것#


시작하기 전에#

다음 환경이 준비되어 있는지 확인하세요:

항목요구 사항확인 방법
Scala 버전2.13.x 또는 3.xscala -version
빌드 도구sbt 1.x 또는 Gradle 8.xsbt --version
IDE (선택)IntelliJ IDEA + Scala 플러그인 또는 VS Code + Metals-
# Scala 버전 확인
scala -version
# 출력 예: Scala code runner version 3.3.1

# sbt 버전 확인
sbt --version
# 출력 예: sbt version in this project: 1.9.7

1단계: 에러 메시지 분석#

1.1 필요한 타입 확인#

에러 메시지에서 필요한 암시적 타입을 정확히 파악하세요:

// 에러: could not find implicit value for parameter ord: Ordering[Person]
case class Person(name: String, age: Int)

val people = List(Person("Alice", 30), Person("Bob", 25))
people.sorted  // Ordering[Person] 필요함

1.2 스코프 확인#

암시적 값은 다음 우선순위로 검색됩니다:

우선순위검색 위치예시
1현재 스코프의 명시적 정의implicit val, given
2명시적 importimport MyImplicits._
3컴패니언 객체object Person { implicit val ord = ... }
4타입의 슈퍼타입 컴패니언상속 관계의 컴패니언 객체
5패키지 객체package object mypackage

2단계: 컴파일러 디버깅 플래그 사용#

-Xlog-implicits 플래그#

sbt에서 다음 옵션을 추가하세요:

// build.sbt
scalacOptions += "-Xlog-implicits"

컴파일 후 다음과 같은 출력을 확인하세요:

[info] /path/to/file.scala:10: Ordering.ordered is not a valid implicit value
[info] for Ordering[Person] because:
[info] hasMatchingSymbol reported error: type mismatch;
[info]  found   : Ordering[Comparable[Person]]
[info]  required: Ordering[Person]

성공 확인: 위와 같은 상세 로그가 출력되면 플래그가 정상 적용된 것입니다.

향상된 에러 메시지#

Scala 3는 기본적으로 더 상세한 에러 메시지와 해결 제안을 제공합니다:

-- Error: /path/to/file.scala:10:8 ------
10 |  people.sorted
   |         ^
   |No given instance of type Ordering[Person] was found
   |for parameter ord of method sorted in trait SeqOps
   |
   |The following import might fix the problem:
   |
   |  import scala.math.Ordering.Implicits._

성공 확인: 컴파일러가 import 제안을 보여주면 Scala 3의 향상된 진단이 작동하는 것입니다.

IDE 설정#

  1. PreferencesBuild, Execution, DeploymentCompilerScala Compiler로 이동하세요
  2. Additional compiler options-Xlog-implicits 추가하세요 (Scala 2)
  3. Ctrl+Shift+P (Windows/Linux) 또는 Cmd+Shift+P (macOS)로 암시적 힌트를 토글하세요

성공 확인: 코드에서 암시적 파라미터가 회색 텍스트로 표시됩니다.

  1. 명령 팔레트(Ctrl+Shift+P)를 열고 Metals: Toggle inlay hints를 실행하세요
  2. 설정에서 metals.inlayHints.implicitArguments.enabletrue로 설정하세요

성공 확인: 코드에서 암시적 파라미터가 인라인 힌트로 표시됩니다.


3단계: 해결 방법#

3.1 암시적 값 직접 정의#

case class Person(name: String, age: Int)

object Person {
  implicit val ordering: Ordering[Person] = Ordering.by(_.age)
}

// 이제 정상 동작
val people = List(Person("Alice", 30), Person("Bob", 25))
people.sorted  // List(Person("Bob", 25), Person("Alice", 30))
case class Person(name: String, age: Int)

object Person:
  given Ordering[Person] = Ordering.by(_.age)

// 이제 정상 동작
val people = List(Person("Alice", 30), Person("Bob", 25))
people.sorted  // List(Person("Bob", 25), Person("Alice", 30))

3.2 기존 암시적 값 활용#

이미 존재하는 암시적 값을 조합하세요:

case class Person(name: String, age: Int)

object Person {
  // String의 Ordering을 활용
  implicit val ordering: Ordering[Person] = Ordering.by(_.name)
}
case class Person(name: String, age: Int)

object Person:
  // 기존 given 인스턴스 활용
  given Ordering[Person] = Ordering.by(_.name)

3.3 명시적으로 전달#

암시적 검색이 복잡할 때는 명시적으로 전달하세요:

// 명시적으로 Ordering 전달
people.sorted(Ordering.by[Person, Int](_.age))
// using 키워드로 명시적 전달
people.sorted(using Ordering.by[Person, Int](_.age))

4단계: 흔한 실수와 해결#

4.1 타입 불일치#

주의
와일드카드 타입(_)은 암시적 값으로 사용할 수 없습니다.
// 잘못된 예: 타입 파라미터 누락
implicit val ord: Ordering[_] = Ordering.by(_.toString)  // 컴파일 안 됨

// 올바른 예: 정확한 타입 지정
implicit val ord: Ordering[Person] = Ordering.by(_.name)

4.2 import 누락#

// JSON 라이브러리 사용 시 흔한 실수
import io.circe.generic.auto._  // 이 import가 필요함

case class User(name: String)
val json = User("Alice").asJson  // Encoder[User] 필요

해결: 라이브러리 문서에서 필요한 import를 확인하세요.

4.3 스코프 문제#

// 잘못된 예: 메서드 내부에 정의하면 외부에서 사용 불가
def process(): Unit = {
  implicit val ord: Ordering[Person] = Ordering.by(_.age)
}

// 올바른 예: 적절한 스코프에 정의
object Implicits {
  implicit val personOrdering: Ordering[Person] = Ordering.by(_.age)
}

import Implicits._

4.4 암시적 충돌#

동일 타입의 암시적 값이 여러 개 있으면 충돌이 발생합니다:

// 에러: ambiguous implicit values
implicit val byAge: Ordering[Person] = Ordering.by(_.age)
implicit val byName: Ordering[Person] = Ordering.by(_.name)

people.sorted  // 어떤 것을 사용해야 할지 모름

해결: 하나만 import하거나 명시적으로 전달하세요.


체크리스트#

암시적 값을 찾지 못할 때 다음을 확인하세요:

  • 타입이 정확히 일치하는가? - 제네릭 타입 파라미터 포함
  • 스코프에 있는가? - import 또는 컴패니언 객체 확인
  • 컴파일 순서가 맞는가? - 암시적 정의가 사용 전에 컴파일되어야 함
  • 충돌하는 암시적 값이 없는가? - 동일 타입의 여러 암시적 값 확인
  • 디버깅 플래그를 사용했는가? - -Xlog-implicits (Scala 2)

모든 항목을 확인했는데도 문제가 해결되지 않으면, 최소 재현 코드를 만들어 Scala Discord나 Stack Overflow에 질문하세요.


관련 문서#