수색…


통사론

  • 암시 적 val x : T = ???

비고

암시 적 클래스를 사용하면 코드를 수정하지 않고도 기존 메서드에 사용자 지정 메서드를 추가 할 수 있으므로 코드를 제어하지 않고도 형식을 풍부하게 만들 수 있습니다.

암시 적 유형을 사용하여 기존 클래스를 풍부하게하는 것은 흔히 '내 라이브러리를 풍부하게합니다'패턴이라고합니다.

암시 적 클래스에 대한 제한 사항

  1. 암시 적 클래스는 다른 클래스, 객체 또는 특성 내에 만 존재할 수 있습니다.
  2. 암시 적 클래스는 암시 적이 아닌 기본 생성자 매개 변수 하나만 가질 수 있습니다.
  3. 암시 적 클래스와 이름이 같은 동일한 범위 내에 다른 객체, 클래스, 특성 또는 클래스 멤버 정의가 없을 수 있습니다.

암시 적 변환

암시 적 변환을 사용하면 컴파일러는 한 유형의 객체를 다른 유형으로 자동 변환 할 수 있습니다. 이렇게하면 코드가 객체를 다른 유형의 객체로 처리 할 수 ​​있습니다.

case class Foo(i: Int)

// without the implicit
Foo(40) + 2    // compilation-error (type mismatch)

// defines how to turn a Foo into an Int
implicit def fooToInt(foo: Foo): Int = foo.i

// now the Foo is converted to Int automatically when needed
Foo(40) + 2    // 42

변환은 단방향입니다 :이 경우 42Foo(42) 다시 변환 할 수 없습니다. 이렇게하려면 두 번째 암시 적 변환을 정의해야합니다.

implicit def intToFoo(i: Int): Foo = Foo(i)

이것은 float 값을 정수 값에 추가 할 수있는 메커니즘입니다.

묵시적 전환은 일어나는 일을 난처하게하기 때문에 조심스럽게 사용해야합니다. 암시 적 변환을 사용하여 명백한 가독성 이득이 없으면 메서드 호출을 통해 명시 적 변환을 사용하는 것이 가장 좋습니다.

암시 적 변환에 중요한 성능 영향은 없습니다.

스칼라는 자바에서 스칼라로 변환하는 모든 변환을 포함하여 scala.Predef 에서 다양한 암시 적 변환을 자동으로 가져옵니다. 이는 기본적으로 모든 파일 편집에 포함됩니다.

암시 적 매개 변수

암시 적 매개 변수는 유형의 매개 변수가 범위에서 한 번 정의 된 다음 해당 유형의 값을 사용하는 모든 함수에 적용되어야하는 경우 유용 할 수 있습니다.

일반적인 함수 호출은 다음과 같습니다.

// import the duration methods
import scala.concurrent.duration._

// a normal method:
def doLongRunningTask(timeout: FiniteDuration): Long = timeout.toMillis

val timeout = 1.second
// timeout: scala.concurrent.duration.FiniteDuration = 1 second

// to call it
doLongRunningTask(timeout) // 1000

이제 모든 메소드에 타임 아웃 지속 시간이 있으며, 동일한 타임 아웃을 사용하여 모든 메소드를 호출하려고합니다. 시간 제한을 암시 적 변수로 정의 할 수 있습니다.

// import the duration methods
import scala.concurrent.duration._

// dummy methods that use the implicit parameter
def doLongRunningTaskA()(implicit timeout: FiniteDuration): Long = timeout.toMillis
def doLongRunningTaskB()(implicit timeout: FiniteDuration): Long = timeout.toMillis

// we define the value timeout as implicit
implicit val timeout: FiniteDuration = 1.second

// we can now call the functions without passing the timeout parameter
doLongRunningTaskA() // 1000
doLongRunningTaskB() // 1000

이것이 작동하는 방식은 scalac 컴파일러가 암시 적 으로 표시되고 범위가 암시 적 매개 변수 중 하나 와 일치 하는 범위의 값을 찾는 것입니다. 발견되면 암시 적 매개 변수로 적용됩니다.

범위에서 같은 유형의 두 개 또는 그 이상의 함축을 정의하면이 기능이 작동하지 않습니다.

오류 메시지를 사용자 정의하려면 유형에 implicitNotFound 주석을 사용하십시오.

@annotation.implicitNotFound(msg = "Select the proper implicit value for type M[${A}]!")
case class M[A](v: A) {}

def usage[O](implicit x: M[O]): O = x.v

//Does not work because no implicit value is present for type `M[Int]`
//usage[Int]   //Select the proper implicit value for type M[Int]!
implicit val first: M[Int] = M(1)
usage[Int]     //Works when `second` is not in scope
implicit val second: M[Int] = M(2)
//Does not work because more than one implicit values are present for the type `M[Int]`
//usage[Int]   //Select the proper implicit value for type M[Int]!

타임 아웃은 이것에 대한 일반적인 사용 사례입니다. 예를 들어 Akka 에서 ActorSystem은 (대부분의 경우) 항상 동일하므로 대개 암묵적으로 전달됩니다. 또 하나의 유스 케이스는 라이브러리 디자인이며, 가장 일반적으로 typeclasses (예 : 스 카즈 , 고양이 또는 휴거 )에 의존하는 FP 라이브러리를 사용합니다.

일반적으로 Int , Long , String 등의 기본 유형에 암시 적 매개 변수를 사용하는 것은 나쁜 습관으로 간주됩니다. 혼동을 일으키고 코드를 읽기 쉽게 만듭니다.

암시 적 클래스

암시 적 클래스를 사용하면 이전에 정의한 클래스에 새 메서드를 추가 할 수 있습니다.

String 클래스에는 withoutVowels 메서드가 없습니다. 다음과 같이 추가 할 수 있습니다.

object StringUtil {
  implicit class StringEnhancer(str: String) {
    def withoutVowels: String = str.replaceAll("[aeiou]", "")
  }
}

암시 적 클래스에는 확장하려는 유형 ( String )과 유형 ( withoutVowels )에 "추가"할 메소드가 포함 된 단일 생성자 매개 변수 ( str )가 있습니다. 새로 정의 된 메서드를 향상된 형식에서 직접 사용할 수 있습니다 (향상된 형식이 암시 적 범위에있는 경우).

import StringUtil.StringEnhancer // Brings StringEnhancer into implicit scope

println("Hello world".withoutVowels) // Hll wrld

후드 아래에서 암시 적 클래스는 다음과 같이 향상된 형식에서 암시 적 클래스로의 암시 적 변환 을 정의합니다.

implicit def toStringEnhancer(str: String): StringEnhancer = new StringEnhancer(str)

암시 적 클래스는 종종 런타임 객체를 만들지 않으므로 런타임 오버 헤드를 제거하기 위해 값 클래스 로 정의됩니다.

implicit class StringEnhancer(val str: String) extends AnyVal {
    /* conversions code here */
}

위의 향상된 정의를 사용하면 withoutVowels 메서드가 호출 될 때마다 StringEnhancer 의 새 인스턴스를 만들 필요가 없습니다.

'암시 적으로'암시 적 매개 변수를 사용하여 해결

하나 이상의 암시 적 매개 변수가있는 암시 적 매개 변수 목록을 가정합니다.

case class Example(p1:String, p2:String)(implicit ctx1:SomeCtx1, ctx2:SomeCtx2)

이제 암시 적 인스턴스 중 하나를 사용할 수없는 경우 ( SomeCtx1 ) 필요한 다른 모든 암시 적 인스턴스가 범위 내에있는 경우 클래스의 인스턴스를 만들려면 SomeCtx1 인스턴스를 제공해야합니다.

이것은 implicitly 키워드를 사용하여 범위 내 암시 적 인스턴스를 서로 보존하면서 수행 할 수 있습니다.

Example("something","somethingElse")(new SomeCtx1(), implicitly[SomeCtx2])

REPL의 내포

REPL 세션 중에 범위 내 모든 implicits 를 보려면 :

scala> :implicits

Predef.scala 정의 된 암시 적 변환도 포함하려면 다음을 Predef.scala .

scala> :implicits -v

표현식을 가지고 있고 그것에 적용되는 모든 다시 쓰기 규칙의 효과를 보려면 (implicit 포함) :

scala> reflect.runtime.universe.reify(expr) // No quotes. reify is a macro operating directly on code.

(예:

scala> import reflect.runtime.universe._
scala> reify(Array("Alice", "Bob", "Eve").mkString(", "))
resX: Expr[String] = Expr[String](Predef.refArrayOps(Array.apply("Alice", "Bob", "Eve")(Predef.implicitly)).mkString(", "))

)



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow