스칼라 식별자는 "암시 적으로"무엇입니까?


169

implicitly스칼라 예제에서 사용되는 이름의 함수를 보았습니다 . 그것은 무엇이며 어떻게 사용됩니까?

여기 예 :

scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
     |                         implicit def stringImpl = new Foo[String] {
     |                             def apply(list : List[String]) = println("String")
     |                         }
     |                         implicit def intImpl = new Foo[Int] {
     |                             def apply(list : List[Int]) =  println("Int")
     |                         }
     |                     } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit

scala> foo(1)
<console>:8: error: type mismatch;
 found   : Int(1)
 required: List[?]
       foo(1)
           ^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:8: error: could not find implicit value for evidence parameter of type
 Foo[Double]
       foo(List(1.0))
          ^

implicitly[Foo[A]].apply(x)컴파일러 는 매개 변수를 implicitly[Foo[A]](x)호출 한다는 것을 의미 하므로 작성해야합니다 implicitly.

객체 / 유형 등을 조사하는 방법 도 참조하십시오 . 스칼라 REPL에서? 스칼라는 implicits 어디에서 보는가?

답변:


206

유쾌하게 간단한 방법을 사용해야하는 몇 가지 이유가 있습니다 implicitly.

암시 적 뷰 이해 / 문제 해결

선택의 접두사를 고려할 때 암시 적 뷰가 트리거 될 수 있습니다 (예 : 고려할 수 the.prefix.selection(args)있는 멤버 selection가 포함되지 않은 경우 args( args암시 적 뷰로 변환 한 후에도 ))이 경우 컴파일러는 로컬로 정의 된 암시 적 멤버를 찾습니다. 현재 또는 둘러싸는 범위에서 상속되거나 가져온 범위에서 해당 유형의 함수에서 정의 된 the.prefix유형 selection또는 동등한 암시 적 메소드 가있는 유형의 함수입니다 .

scala> 1.min(2) // Int doesn't have min defined, where did that come from?                                   
res21: Int = 1

scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>

scala> res22(1) // 
res23: AnyRef{def min(i: Int): Int} = 1

scala> .getClass
res24: java.lang.Class[_] = class scala.runtime.RichInt

다음과 같이 표현식이 예상 유형을 준수하지 않는 경우 암시 적 뷰가 트리거 될 수도 있습니다.

scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1

컴파일러는이 함수를 찾습니다.

scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>

컨텍스트 바운드에 의해 도입 된 암시 적 매개 변수 액세스

암시 적 매개 변수는 암시 적 뷰보다 스칼라의 더 중요한 기능 일 것입니다. 형식 클래스 패턴을 지원합니다. 표준 라이브러리는 이것을 몇 곳 scala.Ordering에서 사용 SeqLike#sorted합니다. 사용 방법을 참조하십시오 . 암시 적 매개 변수는 또한 배열 매니페스트 및 CanBuildFrom인스턴스 를 전달하는 데 사용됩니다 .

스칼라 2.8에서는 컨텍스트 바인드라고하는 암시 적 매개 변수에 대한 간단한 구문을 사용할 수 있습니다. 간단히 말해서, type 매개 변수 A를 갖는 메소드는 다음 유형 의 암시 적 매개 변수 를 필요로합니다 M[A].

def foo[A](implicit ma: M[A])

다음과 같이 다시 작성할 수 있습니다.

def foo[A: M]

그러나 암시 적 매개 변수를 전달하지만 이름을 지정하지 않는 요점은 무엇입니까? 메소드를 구현할 때 어떻게 유용 foo합니까?

암시 적 매개 변수를 직접 참조 할 필요가없는 경우가 종종 있으며, 호출 된 다른 메소드에 대한 암시 적 인수로 터널링됩니다. 필요한 경우 컨텍스트 바인딩을 사용하여 간결한 메소드 서명을 유지 implicitly하고 값을 구체화하기 위해 호출 할 수 있습니다.

def foo[A: M] = {
   val ma = implicitly[M[A]]
}

암시 적 매개 변수의 서브 세트를 명시 적으로 전달

타입 클래스 기반 접근 방식을 사용하여 사람을 예쁘게 인쇄하는 메소드를 호출한다고 가정하십시오.

trait Show[T] { def show(t: T): String }
object Show {
  implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
  implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }

  def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}

case class Person(name: String, age: Int)
object Person {
  implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
    def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
  }
}

val p = Person("bob", 25)
implicitly[Show[Person]].show(p)

이름이 출력되는 방식을 바꾸려면 어떻게해야합니까? 명시 적으로 호출 PersonShow하고 대안을 명시 적으로 전달할 수 Show[String]있지만 컴파일러가을 전달하기를 바랍니다 Show[Int].

Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)

2
scala> 1.min (2) res0 : Int = 1 Scala 2.10.3에서 오류 : scala>가 내재적으로 발생합니다. Int => AnyRef {def min (i : Int) : Any}에서 사용 가능한 암시 적 뷰가 없습니다. 암시 적으로 [Int => {def min (i : Int) : Any}]
jhegedus

이 답변은 최신 버전으로 업데이트됩니다.
emeth

1
암시 적으로 [Int => AnyVal {def min (i : Int) : Int}]가 작동합니다. 답변에 수정해야합니다.
Malkaviano

212

ImplicitlyScala 2.8에서 사용 가능하며 Predef 에서 다음 과 같이 정의 됩니다.

def implicitly[T](implicit e: T): T = e

일반적으로 암시 적 유형의 T 사용할 수 있는지 확인 하고 그러한 경우 반환합니다 .

retronym의 프레젠테이션 에서 간단한 예 :

scala> implicit val a = "test" // define an implicit value of type String
a: java.lang.String = test
scala> val b = implicitly[String] // search for an implicit value of type String and assign it to b
b: String = test
scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c
<console>:6: error: could not find implicit value for parameter e: Int
       val c = implicitly[Int]
                         ^

6
이 방법은 정확하게 확인하지 않습니다. 사용 가능한 암시 적 값이 없으면 컴파일 오류가 발생하는 것으로 보이며 값이 있으면 검색하는 것 같습니다. 내가 왜 이것을 사용하고 싶은지에 대한 더 많은 컨텍스트를 제공 할 수 있습니까?
davetron5000

17
implicitly[Ordering[(Int, String)]].compare( (1, "b"), (1, "a") )특히 Context Bound에 의해 도입 된 암시 적 매개 변수를 검색하려면 :def foo[A: Ordering](a1: A, a2: A) = implicitly[Ordering[A]].compare(a1, a2)
retronym

1
위의 비디오 링크에서 retronym의 토론을 보려면 13:50으로 넘어가십시오.
chaotic3quilibrium

-2

"물고기를 가르친다"는 스칼라 도크 야간 에서 현재 이용할 수있는 알파벳 멤버 인덱스를 사용하는 입니다. #패키지 / 클래스 창의 맨 위에 있는 문자 (및 알파벳이 아닌 이름의 경우)는 해당 문자로 시작하는 멤버 이름 (모든 클래스에서)의 인덱스에 대한 링크입니다. I예 를 들어을 선택 하면 링크에서 방문 할 수 있는 implicitly항목이 한 번 표시 Predef됩니다.


46
물론, 스칼라 독은 암묵적으로 아무 말도하지 않으므로 문서화는 거의되지 않습니다. 누군가 그 문서에서만 그 방법이 무엇인지 어떻게 알 수 있습니까? 나는 Scala 문서에 일상적으로 실망합니다. 암시 적으로와 같은 메소드의 동작은 명백하지 않으며 메소드에 대한 문서는 존재하지 않는 것보다 낫습니다. 스택 오버플로에 대해 감사합니다. / end rant
Jeff


4
타입 시그니처는 이것을 잘 문서화합니다.
retronym

21
implicit스칼라에서 중요한 언어 기능인 것으로 보이며, 적절한 설명이 필요합니다. 형식 서명 수만 자세히 설명하는 문서는 실제 답변보다 지적 자체 만족과 비슷합니다. OP가 요청한 특정 질문을 참조하십시오. OP는 무엇이고 어떻게 사용됩니까? 이것으로 대답하지 않거나 실제 링크를 제공하지 않는 야간 문서에도 대답하지 마십시오. scala-lang.org/files/archive/nightly/docs/library/… 이것은 아무것도 가르치지 않습니다. 정품 문서의 예는 Niklaus Wirth 또는 Turbo Pascal을 참조하십시오. -1
Thomas W

3
implicitimplicitly관련,하지만 확실히 구별된다. implicit키워드는 언어의 일부입니다. implicitly표준 라이브러리에서 일반 스칼라 코드로 정의됩니다. 온라인 문서에는 소스 링크가 포함되어 있으므로 질문자와 해당 소스를 참조하는 것이 가장 좋습니다.
랜달 슐츠
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.