2017-09-06 7 views
4

외부 소스에서 역 직렬화되는 몇 가지 규칙을 지정하는 밀폐 된 케이스 클래스 패밀리가 있습니다. 나는 또한 그와 같은 실제 로직을 수행하는 데 몇 인스턴스와 typeclass이 : 이제암시 적 인스턴스가있는 밀폐 케이스 클래스 패밀리와 일치하는 함수를 자동으로 생성하는 방법은 무엇입니까?

import scala.util.Try 

sealed trait ReaderConfig 
case class Substring(begin: Int, end: Int) extends ReaderConfig 
case class Regex(expr: String) extends ReaderConfig 

trait Read[M[_], RC <: ReaderConfig] { 
    def apply(config: RC, raw: String): M[String] 
} 

object Read { 
    implicit val TryReadSubstring: Read[Try, Substring] = (config: Substring, raw: String) => Try { 
    raw.substring(config.begin, config.end) 
    } 
    implicit val TryReadRegex: Read[Try, Regex] = (config: Regex, raw: String) => Try { 
    config.expr.r.findFirstIn(raw).get 
    } 

    trait Helper[RC <: ReaderConfig] { 
    def as[M[_]](implicit read: Read[M, RC]): M[String] 
    } 

    def apply[RC <: ReaderConfig](config: RC)(raw: String) = new Helper[RC] { 
    override def as[M[_]](implicit read: Read[M, RC]): M[String] = read.apply(config,raw) 
    } 
} 

, 올바른 암시를 찾을 아무 문제가 없습니다 구체적인 유형을 사용하는 동안. I 입력하는 (예 I가 상기 한 바와 같이 직렬화 될 때와 같은) 상부의 특성을 갖는 브로있을 때

@ val ok: Try[String] = Read(Substring(0,1))("abc").as[Try] 
ok: Try[String] = Success("a") 
@ val Fail: Try[String] = Read(Substring(1000,9001))("abc").as[Try] 
Fail: Try[String] = Failure(
    java.lang.StringIndexOutOfBoundsException: String index out of range: 9001 
) 

, 그것은 예상대로 컴파일 실패

@ val config: ReaderConfig = Substring(0,1) 
config: ReaderConfig = Substring(0, 1) 
@ val fail2: Try[String] = Read(config)("abc").as[Try] 
cmd8.sc:1: could not find implicit value for parameter read: $sess.cmd2.Read[scala.util.Try,$sess.cmd1.ReaderConfig] 
val fail2: Try[String] = Read(config)("abc").as[Try] 
              ^
Compilation Failed 

유일한 솔루션 I 같은 올바른 인스턴스와 실제 유형을 일치하는 함수를 작성하는 것입니다 내놓았다 :

val tryRead: ReaderConfig => String => Try[String] = {rc => raw => rc match { 
    case s: Substring => Read[Substring](s)(raw).as[Try] 
    case r: Regex => Read[Regex](r)(raw).as[Try] 
}} 

는 그 다음 행복하게 컴파일하고 내가 그 상황에서 사용할 수 있습니다. 컴파일러는 case의 누락에 대해 나에게 경고해야하므로

@ tryRead(config)("abc") 

res9: Try[String] = Success("a") 

형질

는 밀봉되어 있지만, 분명히 그것은 최대한 빨리 해당 인스턴스의 이상을 가지고 매우 성가신 것으로 판명됩니다.

이 기능을 자동으로 생성 할 수있는 방법이 있습니까? 결국은 case을 복사하여 붙여 넣고 변수 패턴을 채워서 만들 수있는 것입니다.

답변

2

더 일반적인 패턴은 하위 유형 당 하나의 인스턴스가 아닌 수퍼 유형 (ReaderConfig)에 대한 단일 유형 인스턴스를 작성하는 것입니다. 그런 다음 스마트 생성자를 사용하여 ReaderConfig을 만듭니다. 예를 들어 고양이는 Option에 대해 somenone 생성자를 제공합니다. 42.someSome[Int] 대신 Option[Int]을 반환합니다.