암시 스칼라 이민자에 대한 질문은 것 같다 : 어디 implicits에 대한 컴파일러의 모습입니까? 나는 질문이 전혀없는 것처럼 질문이 완전히 형성되는 것처럼 보이지 않기 때문에 암시 적 의미입니다. 🙂 예를 들어 integral
아래 값은 어디에서 오는가?
scala> import scala.math._
import scala.math._
scala> def foo[T](t: T)(implicit integral: Integral[T]) {println(integral)}
foo: [T](t: T)(implicit integral: scala.math.Integral[T])Unit
scala> foo(0)
scala.math.Numeric$IntIsIntegral$@3dbea611
scala> foo(0L)
scala.math.Numeric$LongIsIntegral$@48c610af
첫 번째 질문에 대한 답을 배우기로 결정한 사람들이 따라야 할 또 다른 질문은 명백한 모호성이있는 특정 상황에서 컴파일러가 사용하는 암시 적을 어떻게 선택합니까?
예를 들어 하나에서 다른로 scala.Predef
두 가지 변환을 정의 합니다 . 그러나 두 클래스 모두 많은 메소드를 공유하므로 Scala가 호출 할 때 모호함에 대해 불평하지 않는 이유는 무엇입니까?String
WrappedString
StringOps
map
참고 : 이 질문은 더 일반적인 방식으로 문제를 진술하기 위해이 다른 질문 에서 영감을 얻었습니다 . 답변에서 참조되었으므로 예제가 거기에서 복사되었습니다.
답변
암시 적 유형
스칼라의 내포는 “자동”으로 전달 될 수있는 값을 말하거나 한 유형에서 다른 유형으로 자동 변환되는 값을 말합니다.
암시 적 변환
하나는 메소드를 호출하는 경우, 후자의 유형에 대한 매우 간략하게 말하기 m
객체에 대한 o
클래스를 C
, 그 클래스가 지원 방법을하지 않습니다 m
, 다음 스칼라에서 암시 적 변환을 찾을 것입니다 C
뭔가 수행 지원 m
. 간단한 예제는 방법이 될 것이다 map
에 String
:
"abc".map(_.toInt)
String
방법을 지원하지 않습니다 map
만, StringOps
수행, 그리고에서 암시 적 변환 거기 String
에 StringOps
(참조 가능 implicit def augmentString
에 Predef
).
암시 적 매개 변수
다른 종류의 암시 적은 암시 적 매개 변수 입니다. 이것들은 다른 매개 변수와 마찬가지로 메서드 호출에 전달되지만 컴파일러는 자동으로 채우기를 시도합니다. 그렇게 할 수 없다면 불평 할 것입니다. 하나는 수 하나를 사용하는 방법이다, 명시 적으로 이러한 매개 변수를 전달 breakOut
(예를 들어,에 대한 질문을보고 breakOut
당신이 도전까지 기분이 하루에).
이 경우 foo
메소드 선언 과 같이 암시 적 필요성을 선언해야합니다 .
def foo[T](t: T)(implicit integral: Integral[T]) {println(integral)}
경계보기
암시 적이 암시 적 변환과 암시 적 매개 변수 둘 다인 상황이 있습니다. 예를 들면 다음과 같습니다.
def getIndex[T, CC](seq: CC, value: T)(implicit conv: CC => Seq[T]) = seq.indexOf(value)
getIndex("abc", 'a')
getIndex
클래스에서로 사용할 수있는 암시 적 변환이있는 한이 메서드 는 모든 개체를받을 수 있습니다 Seq[T]
. 그 때문에 a String
를 전달 getIndex
하면 작동합니다.
내부적으로 컴파일러는 변화 seq.IndexOf(value)
에 conv(seq).indexOf(value)
.
이것은 쓸만한 구문 설탕이 있기에 매우 유용합니다. 이 구문 설탕을 사용하여 다음 getIndex
과 같이 정의 할 수 있습니다.
def getIndex[T, CC <% Seq[T]](seq: CC, value: T) = seq.indexOf(value)
이는 문법적으로는 기재되어 결합도 유사한, 상한 ( CC <: Seq[Int]
) 또는 하한 ( T >: Null
).
컨텍스트 바운드
암시 적 매개 변수의 또 다른 일반적인 패턴은 유형 클래스 패턴 입니다. 이 패턴을 사용하면 선언하지 않은 클래스에 공통 인터페이스를 제공 할 수 있습니다. 브리지 패턴과 관심사 분리를위한 어댑터 및 어댑터 패턴의 역할을 모두 수행 할 수 있습니다.
Integral
당신이 언급 한 클래스 타입 클래스 패턴의 전형적인 예이다. 스칼라 표준 라이브러리의 또 다른 예는 Ordering
입니다. 이 패턴을 많이 사용하는 라이브러리 인 Scalaz가 있습니다.
다음은 그 사용 예입니다.
def sum[T](list: List[T])(implicit integral: Integral[T]): T = {
import integral._ // get the implicits in question into scope
list.foldLeft(integral.zero)(_ + _)
}
컨텍스트 바운드 (context bound) 라고 불리는 구문 설탕도 암시 적을 참조 할 필요성이 덜 유용합니다. 해당 방법을 직접 변환하면 다음과 같습니다.
def sum[T : Integral](list: List[T]): T = {
val integral = implicitly[Integral[T]]
import integral._ // get the implicits in question into scope
list.foldLeft(integral.zero)(_ + _)
}
컨텍스트 바운드는이 를 사용하는 다른 메소드 로 전달 해야 할 때 더 유용 합니다. 예를 들어, sorted
on 메소드 Seq
는 내재적이어야합니다 Ordering
. 메소드를 작성하기 위해 다음을 작성할 reverseSort
수 있습니다.
def reverseSort[T : Ordering](seq: Seq[T]) = seq.sorted.reverse
때문에 Ordering[T]
암시에 전달 reverseSort
, 그 다음에 암시 적으로 전달할 수 있습니다 sorted
.
내재는 어디에서 왔습니까?
컴파일러가 객체 클래스에 존재하지 않는 메서드를 호출하거나 암시 적 매개 변수가 필요한 메서드를 호출하기 때문에 암시 적 필요성이 확인되면 필요에 맞는 암시 적을 검색합니다. .
이 검색은 어떤 암시 적이 보이고 어떤 것이 보이지 않는지를 정의하는 특정 규칙을 따릅니다. 컴파일러가 암시 적을 검색 할 위치를 보여주는 다음 표는 Josh Suereth의 암시 적에 대한 훌륭한 프레젠테이션 에서 발췌 한 것으로 Scala 지식을 향상시키려는 모든 사람에게 진심으로 권장합니다. 그 이후로 피드백과 업데이트로 보완되었습니다.
아래 1 번 항목에서 사용 가능한 암시 적은 2 번 항목보다 우선합니다. 그 외에, 암시 적 매개 변수의 유형과 일치하는 적합한 인수가 여러 개있는 경우 정적 오버로드 해결 규칙을 사용하여 가장 구체적인 인수가 선택됩니다 (스칼라 참조). 사양 §6.26.3). 더 자세한 정보는이 답변의 끝에 링크 된 질문에서 찾을 수 있습니다.
- 현재 범위에서 먼저 살펴보기
- 현재 범위에 정의 된 암시 적
- 명시 적 수입
- 와일드 카드 수입
다른 파일에서 동일한 범위
- 이제 관련 유형을 살펴보십시오.
- 유형의 컴패니언 객체
- 인수 유형의 암시 적 범위 (2.9.1)
- 암시 적 유형 인수 범위 (2.8.0)
- 중첩 유형의 외부 객체
- 다른 치수
그들에게 몇 가지 예를 들어 보자.
현재 범위에서 정의 된 암시 적
implicit val n: Int = 5
def add(x: Int)(implicit y: Int) = x + y
add(5) // takes n from the current scope
명시 적 수입
import scala.collection.JavaConversions.mapAsScalaMap
def env = System.getenv() // Java map
val term = env("TERM") // implicit conversion from Java Map to Scala Map
와일드 카드 수입
def sum[T : Integral](list: List[T]): T = {
val integral = implicitly[Integral[T]]
import integral._ // get the implicits in question into scope
list.foldLeft(integral.zero)(_ + _)
}
다른 파일에서 동일한 범위
편집 : 이것은 다른 우선 순위가없는 것 같습니다. 우선 순위 구분을 보여주는 예가있는 경우 의견을 작성하십시오. 그렇지 않으면, 이것에 의존하지 마십시오.
이것은 첫 번째 예와 같지만 내재적 정의가 사용법과 다른 파일에 있다고 가정합니다. 패키지 객체를 사용하여 암시 적 방법을 참조하십시오 .
유형의 동반 객체
여기에 주목할 두 가지 객체 동반자가 있습니다. 먼저 “소스”유형의 객체 동반자를 살펴 봅니다. 예를 들어 객체 내부에 Option
로의 암시 적 변환이 Iterable
있으므로에 Iterable
메소드를 호출 하거나을 (를) 기대하는 무언가를 Option
전달할 Option
수 Iterable
있습니다. 예를 들면 다음과 같습니다.
for {
x <- List(1, 2, 3)
y <- Some('x')
} yield (x, y)
그 표현은 컴파일러에 의해
List(1, 2, 3).flatMap(x => Some('x').map(y => (x, y)))
그러나 List.flatMap
기대 TraversableOnce
하는 Option
없습니다. 컴파일러는 내부 모습 Option
의 객체 동반자와의 변환 발견 Iterable
이다, TraversableOnce
이 표현이 정확하기를.
둘째, 예상 유형의 컴패니언 개체 :
List(1, 2, 3).sorted
이 메서드 sorted
는 암시 적 Ordering
입니다. 이 경우 객체 내부를 살펴보고 Ordering
클래스 Ordering
와 동반 하여 암시 적 위치를 찾습니다 Ordering[Int]
.
수퍼 클래스의 컴패니언 객체도 살펴 봅니다. 예를 들면 다음과 같습니다.
class A(val n: Int)
object A {
implicit def str(a: A) = "A: %d" format a.n
}
class B(val x: Int, y: Int) extends A(y)
val b = new B(5, 2)
val s: String = b // s == "A: 2"
이것이 Scala 가 내부 에서 발견되는 것처럼 암시 Numeric[Int]
적이고 Numeric[Long]
귀하의 질문에서 발견 한 방법 입니다.Numeric
Integral
인수 유형의 암시 적 범위
인수 type이있는 메소드가 있으면 A
암시 적 유형의 범위 A
도 고려됩니다. “암시 적 범위”는 이러한 모든 규칙이 재귀 적으로 적용됨을 의미합니다. 예를 들어 A
위의 규칙에 따라 동반 객체 에서 암시 적을 검색합니다.
이는 A
해당 매개 변수의 변환에 대한 암시 적 범위 가 검색되는 것이 아니라 전체 표현식에 대한 검색을 의미합니다 . 예를 들면 다음과 같습니다.
class A(val n: Int) {
def +(other: A) = new A(n + other.n)
}
object A {
implicit def fromInt(n: Int) = new A(n)
}
// This becomes possible:
1 + new A(1)
// because it is converted into this:
A.fromInt(1) + new A(1)
Scala 2.9.1부터 사용할 수 있습니다.
형식 인수의 암시 적 범위
이것은 타입 클래스 패턴이 실제로 작동하기 위해 필요합니다. Ordering
예를 들어 다음과 같이 고려하십시오 . 컴패니언 객체에 암시 적 요소가 포함되어 있지만 추가 할 수는 없습니다. 그렇다면 어떻게 Ordering
자동으로 찾은 자신 만의 수업을 만들 수 있습니까?
구현부터 시작하겠습니다.
class A(val n: Int)
object A {
implicit val ord = new Ordering[A] {
def compare(x: A, y: A) = implicitly[Ordering[Int]].compare(x.n, y.n)
}
}
따라서 전화 할 때 어떤 일이 발생하는지 고려하십시오
List(new A(5), new A(2)).sorted
우리가 보았 듯이,이 방법 sorted
은 Ordering[A]
(실제로 Ordering[B]
어디를 기대합니다 B >: A
)를 기대합니다 . 내부 Ordering
에는 그런 것이 없으며 볼 소스 유형이 없습니다. 물론, 내부를 찾는 A
인 형식 인수 의 Ordering
.
이것은 다양한 수집 방법이 CanBuildFrom
작동 하는 방식이기도합니다 CanBuildFrom
.
참고 : Ordering
는로 정의되며 trait Ordering[T]
, 여기서 T
유형 매개 변수입니다. 이전에는 스칼라가 유형 매개 변수 내부를 살펴 보았으며 이는별로 의미가 없습니다. 상기 찾았다 암시이다 Ordering[A]
여기서, A
파라미터를 입력하지 실제 유형 : 이는 인 형식 인수 로 Ordering
. 스칼라 사양의 7.2 절을 참조하십시오.
Scala 2.8.0부터 사용할 수 있습니다.
중첩 유형의 외부 객체
나는 실제로 이것의 예를 보지 못했다. 누군가 공유 할 수 있으면 감사하겠습니다. 원칙은 간단합니다.
class A(val n: Int) {
class B(val m: Int) { require(m < n) }
}
object A {
implicit def bToString(b: A#B) = "B: %d" format b.m
}
val a = new A(5)
val b = new a.B(3)
val s: String = b // s == "B: 3"
다른 차원
나는 이것이 농담이었을 것이라고 확신하지만,이 답변은 최신이 아닐 수도 있습니다. 따라서이 문제를 최종 중재인으로 생각하지 마십시오. 오래된 정보가 발견되면 문제를 해결할 수 있도록 알려주십시오.
편집하다
관심있는 관련 질문 :
답변
나는 암시 적 매개 변수 해결의 우선 순위를 찾고 싶었을뿐 아니라 수입 세금없이 암시 적을 재검토 하는 블로그 게시물을 작성했습니다 (그리고 피드백 후 암시 적 매개 변수 우선 순위 ).
목록은 다음과 같습니다.
- 1) 로컬 선언, 가져 오기, 외부 범위, 상속, 접두사없이 액세스 할 수있는 패키지 객체를 통해 현재 호출 범위에 암시 적 표시
- 2) 암시 적 범위 는 검색하는 암시 적 유형과 관계가있는 모든 종류의 컴패니언 객체 및 패키지 객체를 포함합니다. 해당되는 경우 해당 매개 변수 및 수퍼 타입 및 수퍼 특성).
어느 단계에서든 둘 이상의 암시 적 정적 오버로드 규칙을 사용하여이를 해결합니다.