[Scala 필기-도]Scala 암시 적 Implicit

21655 단어 Scala
스칼라 암시 적
암시 적 인 것 은 도대체 무엇 입 니까?
scala 중 은 식 은 자바 에 비해 새로운 특성 이다.그렇다면 암시 적 인 것 은 무엇 일 까?암시 적 존재 세 가지 기본 사용 방식:-암시 적 속성-암시 적 방법-암시 적 대상
암시 적 속성 예:
implicit val int size = 5

def caculate(a : Int)(implicit val size) = a * size

이런 상황 에서 암시 적 인 것 은 문맥 속성 으로 입력 하 는 것 이 고 더욱 복잡 한 상황 은 앞에서 말 한 문맥 과 기능 통 제 를 수행 하 는 것 과 같다.그 본질은 자원 의 주입 으로 자원 의 디 스 플레이 설정 을 숨 기거 나 생략 하여 불 러 오 는 목적 을 달성 하 는 것 이다.여기까지 말 하면 Spring 의 IOC 를 쉽게 연상 시 킬 수 있다 고 믿 습 니 다.Spring/Guice 의 IOC 에서 우 리 는 주해/배치 라 는 형식 을 통 해 자원 주입 실례 화 를 실현 합 니 다.Spring/Guice 에서 주 입 된 자원 에 대해 우 리 는 xml 또는 주 해 를 통 해 자원 속성 설정 을 완성 할 수 있 습 니 다.그러나 이러한 방법 은 부족 합 니 다.xml 또는 주해 설정 은 모두 정적 설정 에 속 합 니 다.만약 에 우리 가 동적 특성 이 필요 할 때 추가 로 많은 작업 을 해 야 합 니 다.예 를 들 어 우 리 는 지불 컨트롤 러 가 있 는데 지불 방식 이 달러 일 때 우 리 는 달러 서 비 스 를 사용 해 야 한다.지불 방식 이 인민 폐 를 위해 서 우 리 는 인민폐 서 비 스 를 사용 해 야 한다.
class PayController @Inject()settlementService: SettlementService) { //                ,        

  def doSettle(bill: Bill) = {
    settlementService.doSettle(bill)
  }

}

이러한 결 제 를 실현 하려 면 코드 를 통 해 bill.getType 을 판단 한 후 수 동 으로 해당 하 는 결제 기능 을 실현 해 야 합 니 다.하지만 이렇게 결합 을 도입 했다.
한편,암시 적 속성 은 더 좋 은 방식 임 에 틀림없다.여기 서 결제 방식 을 자 유 롭 게 주입 할 수 있다.

class PayController ()(implicit val settlementService: SettlementService) {
  def doSettle(bill: Bill) = {
    settlementService.doSettle(bill)
  }
}

함수 방법 은 본질 적 으로 일종 의 전환 을 하 는 것 이다.이런 전환 은 문맥 에 의존 하지 않 는 다.즉,f(a)=>b 는 다른 상태 에 영향 을 주지 않 고 부작용 이 없다 고 할 수 있다.암시 적 함수 방법 은 본질 적 으로 함수 방법 이기 도 하고 요소 에 대한 전환 관계 로 볼 수 있 으 며 a=>b.자바 에서 facade 모드 는 비교적 자주 사용 하 는 모드 로 facade 모드 는 인터페이스 정보 에 대한 패 키 징 을 제공 합 니 다.시스템 개발 이나 업무 개발 에서 facade 모델 은 사용 이 비교적 빈번 합 니 다.자바 에서 우 리 는 서로 다른 시스템 인터페이스 에 대응 하여 서로 다른 facade 를 제공 할 수 있 지만 서로 다른 facade 의 전환 에 대해 코드 에 수 동 으로 장 착 해 야 합 니 다.방법 급 암시 적 전환 을 통 해 우 리 는 인터페이스 급 의 암시 적 전환 을 편리 하 게 실현 할 수 있다.
예 를 들 어 다음 글 에서 저 희 는 주문 서 를 확대 하고 실제 결 제 된 주문 서 는 온라인 과 오프라인 두 가지 주문 과 관련 될 수 있 지만 최종 주문 정 보 는 내부 의 BillInfo 로 전 환 됩 니 다.여기 서 우 리 는 방법 급 암시 적 전환 을 통 해 OnlineBillFacade/OfflineBillFacade=>BillInfo 를 직접 실현 하고 코드 를 대량으로 판단 하지 않 아 도 논리 적 통 제 를 실현 합 니 다.
sealed trait Bill
case class OnlineBillFacade(count: Int,
                      platform: Platform,
                      currency: Currency) extend Bill

case class OfflineBillFacade(count: Int,
                      address: String,
                      shop: Shop,
                      currency: Currency) extend Bill

case class BillInfo(
                      flowNumber: Long,
                      createTime: Long,
                      state: State,
                      count: Int,
                      platform: Platform,
                      address: String,
                      shop: Shop,
                      currency: Currency) extend Bill


object BillConverter {

  implicit def onlineBill2BillInfo(facade: OnlineBillFacade) : BillInfo = ...
  implicit def offlineBillFacade(facade: OfflineBillFacade) : BillInfo  = ...
}

class PayController ()(implicit val settlementService: SettlementService) {

  def doSettle[T <: bill="" t="" settlementservice.dosettle=""/>

암시 적 대상 에 대해 AOP 사상 에 대한 진일보 한 탐색 임 에 틀림없다.AOP 에서 우 리 는 소스 코드 를 바 꾸 지 않 고 기능 을 추가 하려 고 합 니 다.AOP 에서 우 리 는 동적 대 리 를 통 해 기능 의 확장 을 실현 합 니 다.동적 대 리 를 통 해 우 리 는 절단면 통 제 를 편리 하 게 실현 할 수 있다.절단면 을 대상 으로 프로 그래 밍 하 는 것 은 실제 적 으로 우리 의 모든 것 이 인 터 페 이 스 를 중심 으로 디자인 해 야 한 다 는 전제 가 있다.절단면 이 제어 할 수 있 는 최소 입도 가 바로 방법 급 이다.또한 범 형 설정 이기 때문에 사실상 절단면 에서 알림 을 사용 하려 면 입력 매개 변 수 를 선별 판단 하여 범 형 관 리 를 완성 해 야 한다.이 부분 은 확장 에 불리 하 다.사실은 여기 서 우 리 는 범 형 에 대해 유형 적 인 제약 을 할 방법 이 없다.
한편,암시 적 대상 은 우리 에 게 새로운 가능성 을 가 져 다 주 었 다.암시 적 대상 은 POJO 를 대상 으로 하기 때문에 암시 적 대상 은 AOP 에 비해 더욱 가 는 입도 통 제 를 가진다.또한 POJO 를 대상 으로 하기 때문에 암시 적 대상 은 경계 정 의 를 할 필요 가 없다.암시 적 대상 을 통 해 우 리 는 기 존 코드 를 바 꾸 지 않 고 기능 의 확장 을 실현 할 수 있다.
활용 단어 참조
  • 집행 상하 문
  • 기능 제어
  • 한정 사용 가능 한 실례
  • 암시 적 증거
  • 유형 지우 기
  • 개선 오류
  • 허 유형
  • 실행 문맥
    통용 되 는 상하 문 정 보 는 은 식 을 통 해 결합 을 낮 춘 다
    트 랜 잭 션,데이터베이스 연결,스 레 드 풀,사용자 세 션 을 작성 할 때 암시 적 매개 변수 컨 텍스트 도 사용 하기에 적합 합 니 다.방법 매개 변 수 를 사용 하면 행 위 를 조합 할 수 있 고 방법 매개 변 수 를 암시 적 매개 변수 로 설정 하면 API 를 더욱 간결 하 게 만 들 수 있다.
    //                 
    import scala.concurrent.ExecutionContext.Implicits.global
    
    apply[T](body: => T)(implicit executor: ExecutionContext): Future[T]

    기능 제어
    권한 수여 토 큰 을 도입 함으로써 저 희 는 특정한 API 작업 을 일부 사용자 만 호출 할 수 있 도록 제어 할 수 있 습 니 다.저 희 는 권한 수여 토 큰 을 사용 하여 데이터 의 가시 성 을 결정 할 수 있 습 니 다.또한 암시 적 사용자 세 션 매개 변 수 는 이러한 토 큰 정 보 를 포함 할 수 있 습 니 다.
    def createMenu(implicit session: Session): Menu = {
      val defaultItems = List(helpItem, searchItem)
      val accountItems =
      if (session.loggedin()) List(viewAccountItem, editAccountItem)
      else List(loginItem)
      Menu(defaultItems ++ accountItems)
    }

    사용 가능 한 인 스 턴 스 제한
    매개 변수 화 유형 방법 이 있 는 유형 매개 변 수 를 한정 하여 이 매개 변 수 는 특정한 유형의 입력 만 받 도록 합 니 다.
    package implicits
    
    object Implicits {
        import implicits.javadb.JRow
    
    
        implicit class SRow (jrow: JRow){
    
            def get[T](colName: String)(implicit toT: (JRow, String) => T): T =
                toT(jrow, colName)
        }
    
    
        implicit val jrowToInt: (JRow, String) => Int = (jrow: JRow, colName: String) => jrow.getInt(colName)
        implicit val jrowToDouble: (JRow, String) => Double = (jrow: JRow, colName: String) => jrow.getDouble(colName)
        implicit val jrowToString: (JRow, String) => String = (jrow: JRow, colName: String) => jrow.getText(colName)
    
        def main(args: Array[String]) = {
            val row = javadb.JRow("one" -> 1, "two" -> 2.2, "three" -> "THREE!")
            val oneValue1: Int = row.get("one")
            val twoValue1: Double = row.get("two")
            val threeValue1: String = row.get("three")
    //                 val fourValue1: Byte = row.get("four")
            //      
            println(s"one1 -> $oneValue1")
            println(s"two1 -> $twoValue1")
            println(s"three1 -> $threeValue1")
            val oneValue2 = row.get[Int]("one")
            val twoValue2 = row.get[Double]("two")
            val threeValue2 = row.get[String]("three")
    
    //         val fourValue2 = row.get[Byte]("four")
            //      
            println(s"one2 -> $oneValue2")
            println(s"two2 -> $twoValue2")
            println(s"three2 -> $threeValue2")
        }
    }
    
    
    package database_api {
    
        case class InvalidColumnName(name: String)
            extends RuntimeException(s"Invalid column name $name")
    
        trait Row {
            def getInt      (colName: String): Int
            def getDouble   (colName: String): Double
            def getText     (colName: String): String
        }
    }
    
    package javadb {
        import database_api._
    
        case class JRow(representation: Map[String, Any]) extends Row {
            private def get(colName: String): Any =
                representation.getOrElse(colName, throw InvalidColumnName(colName))
    
            def getInt      (colName: String): Int      = get(colName).asInstanceOf[Int]
            def getDouble   (colName: String): Double   = get(colName).asInstanceOf[Double]
            def getText     (colName: String): String   = get(colName).asInstanceOf[String]
        }
    
        object JRow {
            def apply(pairs: (String, Any)*) = new JRow(Map(pairs :_*))
        }
    }
    

    암시 적 증거
    때때로 우 리 는 허용 되 는 유형 만 한정 하고 추가 처 리 를 제공 할 필요 가 없다.다시 말 하면 우 리 는 제시 한 유형 이 우리 의 수 요 를 만족 시 킬 수 있다 는'증거'가 필요 하 다.이제 우 리 는 또 다른 암시 적 증거 라 고 불 리 는 관련 기술 에 대해 허용 되 는 유형 을 한정 하고 이런 유형 들 은 모두 있 는 초 류 를 계승 할 필요 가 없다.
    trait TraversableOnce[+A] ... {
    ...
    def toMap[T, U](implicit ev: <: class="hljs-literal">T, U)]): immutable.Map[T, U]
    ...
    }

    우 리 는 두 가지 유형의 매개 변수 로 구 성 된 유형 을 접두사 표현법 으로 표시 할 수 있다 고 언급 한 적 이 있 습 니 다.따라서 다음 두 가지 표현 식 은 등가 입 니 다.<:b=">A<:b=">는 toMap 에서 B 는 실제 pair:<:u=">입 니 다.
    형식 지우 기
    object M {
    implicit object IntMarker
    implicit object StringMarker
    def m(seq: Seq[Int])(implicit i: IntMarker.type): Unit = println(s"Seq[Int]: $seq")
    def m(seq: Seq[String])(implicit s: StringMarker.type): Unit =
    println(s"Seq[String]: $seq")
    }

    가상 유형 Phantom Type
    형식 지우 기 와 유사 합 니 다.가상 형식 은 태그 에 만 사 용 됩 니 다.
    가상 유형 자 체 는 실제 적 으로 암시 적 전환 의 범주 에 속 하지 않 지만 여 기 는 사실 유형 지우 기 와 사용 에 있어 어느 정도 비슷 한 초기 가 있다.
    가상 유형 은 주로 다음 과 같은 두 가지 장점 이 있 습 니 다.-무효 상 태 를 대표 할 수 없습니다.가장 좋 은 표현 은 List,Cons 와 Nil 의 관계 입 니 다.-유형 등급 의 정 보 를 가지 고 다 니 는 것 입 니 다.
    예 를 들 어 가상 유형 을 통 해 거리 단 위 를 제한 하 는 것 이다.
    case class Distance[A](x: Double) extends AnyVal
    
    case object Kilometer
    case object Mile
    
    def marathonDistance: Distance[Kilometer.type] = Distance[Kilometer.type](42.195)
    
    def distanceKmToMiles(kilos: Distance[Kilometer.type]): Distance[Mile.type] =
        Distance[Mile.type](kilos.x * 0.621371)
    
    def marathonDistanceInMiles: Distance[Mile.type] = distanceKmToMiles( marathonDistance )

    암시 적 오류 보고
    @implicitNotFound(msg =
    "Cannot construct a collection of type ${To} with elements of type ${Elem}" +
    " based on a collection of type ${From}.")
    trait CanBuildFrom[-From, -Elem, +To] {...}

    유형 클래스 모드
    자바 서브 타 입 다 형 과 달리 이 기능 도 특설 다 형(ad hoc polymorphism)scala 자바 의 매개 변수 화 다 형(paremetric polymorphism)이 되 었 습 니 다.
    case class Address(street: String, city: String)
    case class Person(name: String, address: Address)
    trait ToJSON {
    def toJSON(level: Int = 0): String
    val INDENTATION = " "
    def indentation(level: Int = 0): (String,String) =
    (INDENTATION * level, INDENTATION * (level+1))
    }
    implicit class AddressToJSON(address: Address) extends ToJSON {
    def toJSON(level: Int = 0): String = {
    val (outdent, indent) = indentation(level)
    s"""{
    |${indent}"street": "${address.street}",
    |${indent}"city":
    "${address.city}"
    |$outdent}""".stripMargin
    }
    }
    implicit class PersonToJSON(person: Person) extends ToJSON {

    탐구 암시 적
    상기 사용 장면 에서 말 한 바 와 같이 암시 적 인 것 은 scala 에서 우리 에 게 많은 놀 라 움 을 가 져 다 주 었 다.암시 적 인 방식 을 통 해 우 리 는 문맥 처리,경계 처리,유형 지우 기 등 문 제 를 더욱 잘 해결 할 수 있다.
    암시 적 부족
    왜 간단 한 유형+유형 클래스 모드 가 적용 되 지 않 습 니까?
  • 추가 시간 에 암시 적 코드
  • 을 작성 합 니 다.
  • 컴 파일 은 추가 시간 을 소비 합 니 다
  • 운행 비용,암시 적 코드 의 본질은
  • 을 반사 하 는 것 이다.
  • 암시 적 특징 과 다른 스칼라 특징,특히 하위 유형 특징 이 교 집합 될 때 기술적 문제 가 발생 할 수 있 습 니 다[scala-debate email 메 일 팀]
  • trait Stringizer[+T] {
    def stringize: String
    }
    implicit class AnyStringizer(a: Any) extends Stringizer[Any] {
    def stringize: String = a match {
    case s: String => s
    case i: Int => (i*10).toString
    case f: Float => (f*10.1).toString
    case other =>
    throw new UnsupportedOperationException(s"Can't stringize $other")
    }
    }
    val list: List[Any] = List(1, 2.2F, "three", 'symbol)
    list foreach { (x:Any) =>
    try {
    println(s"$x: ${x.stringize}")
    } catch {
    case e: java.lang.UnsupportedOperationException => println(e)
    }
    }

    우 리 는 Stringizer 라 는 추상 체 를 정의 했다.이전 ToJSON 예제 대로 라면 문자열 화 되 기 를 원 하 는 모든 형식 에 암시 적 클래스 를 만 들 것 입 니 다.그 자체 가 문제 다.만약 우리 가 서로 다른 유형의 인 스 턴 스 를 처리 하고 싶다 면,우 리 는 list 형식의 map 방법 에서 Stringizer 인 스 턴 스 를 암시 적 으로 전달 할 수 밖 에 없습니다.따라서 우 리 는 AnyStringerize 류 를 정의 해 야 합 니 다.이 종 류 는 우리 가 알 고 있 는 모든 유형 을 어떻게 처리 하 는 지 알 고 있 습 니 다.이 유형 들 은 이상 한 default 자 구 를 던 지 는 데 도 포함 되 어 있다.이러한 실현 방식 은 매우 아름 답지 않 고 대상 을 대상 으로 프로 그래 밍 하 는 핵심 규칙 에 도 위배 된다.switch 문 구 를 사용 하여 변화 할 수 있 는 유형 을 판단 해 서 는 안 된다.반면,다 중 배포 작업 을 이용 해 야 합 니 다.이 는 toString 방법 이 Scala 와 자바 언어 에서 의 운영 방식 과 유사 합 니 다.
    암시 적 사용 주의
  • 은 언제든지 암시 적 전환 방법 으로 반환 유형 을 지정 해 야 합 니 다.그렇지 않 으 면 유형 이 추정 한 반환 유형 은 예상 치 못 한 결 과 를 초래 할 수 있다.
  • 컴 파일 러 는 사용자 의 전환 을 편리 하 게 수행 할 수 있 지만.그러나 현재 로 서 는 이러한 전환 에 따 른 번 거 로 움 이 유익 하 다.

  • 예 를 들 어 특정한 유형의 정의 방법+를 사용 하고 이 방법 을 해당 유형의 인 스 턴 스 에 적용 하려 고 한다 면 컴 파일 러 는 이 인 스 턴 스 의 toString 방법 을 호출 하여 String 형식의+작업(문자열 통합)을 수행 할 수 있 습 니 다.이것 은 특정한 상황 에서 String 과 같은 잘못된 유형의 이상 한 오 류 를 설명 할 수 있다.
    이와 함께 필요 하 다 면 컴 파일 러 는 방법의 입력 매개 변 수 를 자동 으로 원 그룹 으로 조합 할 것 이다.때때로 이 행 위 는 사람 을 괴 롭 힐 수 있다.다행히도 스칼라 2.11 은 현재 경고 메 시 지 를 던 질 것 이다.
    scala> def m(pair:Tuple2[Int,String]) = println(pair)
    scala> m(1, "two")
    :9: warning: Adapting argument list by creating a 2-tuple:
    this may not be what you want.
    signature: m(pair: (Int, String)): Unit
    given arguments: 1, "two"
    after adaptation: m((1, "two"): (Int, String))
    m(1,"two")

    암시 적 해석 규칙
  • Scala 는 접두사 경 로 를 입력 하지 않 아 도 되 는 형식 호 환 암시 적 값 을 분석 합 니 다.다시 말 하면 암시 적 값 은 같은 역할 영역 에 정의 된다.예 를 들 어 암시 적 값 은 같은 코드 블록 에 정의 되 고 암시 적 값 은 같은 유형 에 정의 되 며 암시 적 값 은 동반 대상 에 정의 되 거나 부모 형식 에 정의 된다.
  • Scala 는 현재 역할 영역 에 가 져 온 암시 적 값 을 분석 합 니 다.(이것 도 접두사 경 로 를 입력 할 필요 가 없습니다.)
  • 암시 적 클래스 Scala 가 일치 합 니 다.일치 도가 가장 높 은 스텔스 를 선택 합 니 다.예 를 들 어 암시 적 매개 변수 유형 이 Foo 형식 이 고 현재 역할 영역 에 Foo 형식의 암시 적 값 도 존재 하 며 AnyRef 형식의 암시 적 값 도 존재 한다 면 Scala 는 Foo 의 암시 적 값 으로 유형 을 선택 할 것 입 니 다.
  • 암시 적 값 이 일치 합 니 다.두 개 이상 의 암시 적 값 은 다른 의 미 를 일 으 킬 수 있 습 니 다(예 를 들 어 같은 유형 을 가지 고 있 습 니 다).컴 파일 오류 가 발생 할 수 있 습 니 다.
  • 좋은 웹페이지 즐겨찾기