如何定义部分参数化泛型隐式类?

时间:2019-05-12 09:26:16

标签: scala implicit-conversion

是否可以定义部分参数化的通用隐式类?例如,假设我有以下课程

  implicit class IoExt[L, R](val io: IO[R]) {
    def wrapped(errorCode: String): IO[Either[ProcessingResult[L], R]] = ???
  }

如何定义类似的内容

type IoExtLocal[R] = IoExt[String, R]

并且IoExtLocal[R]是否可以用作隐式类?

动机是使每次调用wrapped[](..)的客户端代码都不必指定类型参数。它变得非常冗长。

2 个答案:

答案 0 :(得分:3)

只需创建另一个隐式类并导入必要的类

  object ioExt {
    implicit class IoExt[L, R](val io: IO[R]) extends AnyVal {
      def wrapped(errorCode: String): IO[Either[ProcessingResult[L], R]] = ???
    }
  }

  object ioExtLocal { 
    implicit class IoExtLocal[R](val io: IO[R]) extends AnyVal {
      def wrapped(errorCode: String): IO[Either[ProcessingResult[String], R]] = 
        (io: ioExt.IoExt[String, R]).wrapped(errorCode)
    }
  }

  import ioExtLocal._

  trait SomeR
  val x: IO[SomeR] = ???
  x.wrapped(???)

答案 1 :(得分:1)

尝试了多种解决方案后,我发现以下操作无需每次调用​​wrapped时都实例化助手类

trait IoExtTrait[L, R] extends Any {

  protected def io: IO[R]

  def wrapped(errorCode: String): IO[Either[ProcessingResult[L], R]] =
    io.attempt.map(_.leftMap(ex ⇒ FailureMsg[L](errorCode, Some(ex))))

  def wrappedT(errorCode: String): EitherT[IO, ProcessingResult[L], R] =
    EitherT(wrapped(errorCode))
}

implicit class IoExtLocalString[R](protected val io: IO[R]) extends AnyVal with IoExtTrait[String, R] {
  override def wrapped(errorCode: String) = super.wrapped(errorCode)
}

另一方面,每次调用后都会实例化助手类

implicit class IoExtLocalString[R](protected val io: IO[R]) extends AnyVal with IoExtTrait[String, R] {}

如果有人知道为什么会发生,请告诉我。我使用的是Scala 2.12.8(与2.13-RC1的行为相同)。

https://github.com/scala/bug/issues/11526处的进一步交谈确认,两种情况都发生了分配。太糟糕了。