[scala] 스칼라 식별자는 “암시 적으로”무엇입니까?

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 어디에서 보는가?



답변

유쾌하게 간단한 방법을 사용해야하는 몇 가지 이유가 있습니다 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)


답변

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]
                         ^


답변

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


답변