简体   繁体   English

具有多个类型参数的类型类的值类

[英]Value class for type class with multiple type parameters

It is a common practice to provide a helper value class for accessing type classes - something like 通常的做法是提供一个帮助值类来访问类型类 - 比如

object Show {
  def apply[A](implicit sh: Show[A]): Show[A] = sh

  def show[A: Show](a: A) = Show[A].show(a)

  implicit class ShowOps[A: Show](a: A) {
    def show = Show[A].show(a)
  }

  implicit val intCanShow: Show[Int] =
    new Show[Int] {
      def show(int: Int): String = s"int $int"
    }
}

In my case, I have a type class with 2 parameters. 在我的例子中,我有一个带有2个参数的类型。 And I cannot get the value class to work (MapperOps). 我无法让值类工作(MapperOps)。 I keep getting "could not find implicit value for parameter mapper" 我一直在“找不到参数映射器的隐含值”

trait Mapper[T, D] {
  def toDto(i: T): D
}

object Mapper {
  def map[T, D](i: T)(implicit mapper: Mapper[T, D]): D = implicitly[Mapper[T, D]].toDto(i)

  def apply[T, D](implicit mapper: Mapper[T, D]): Mapper[T, D] = mapper

  implicit def optionMapper[T, D](implicit mapper: Mapper[T, D]): Mapper[Option[T], Option[D]] = {
    new Mapper[Option[T], Option[D]] {
      override def toDto(i: Option[T]): Option[D] = i.map(mapper.toDto)
    }
  }

  implicit def seqMapper[T, D](implicit mapper: Mapper[T, D]): Mapper[Seq[T], Seq[D]] = {
    new Mapper[Seq[T], Seq[D]] {
      override def toDto(i: Seq[T]): Seq[D] = i.map(mapper.toDto)
    }
  }
   // Neither works
  implicit class MapperOps1[T,D](a: T) {
     def toDto = Mapper[T,D].toDto(a)
   }
   implicit class MapperOps2[T,D](a: T) {
     def toDto(implicit mapper: Mapper[T,D]) = Mapper[T,D].toDto(a)
   }
   implicit class MapperOps3[T,D](a: T) {
     def toDto[D](implicit mapper: Mapper[T,D]): D Mapper[T,D].toDto(a)
   }
}

Notice the important difference that in 请注意中的重要区别

implicit class ShowOps[A: Show](a: A) { ... }

you have this A : Show part, which essentially desugares into 你有这个A : Show部分,基本上是自省的

implicit class ShowOps[A](a: A)(implicit s: Show[A]) { ... }

Since there is no neat [T : MyTypeClass] -syntax for two-parameter "Type-Pair-Classes", you have to provide the implicit Mapper as a separate parameter to the constructor: 由于双参数“Type-Pair-Classes”没有整洁的[T : MyTypeClass] -syntax,因此必须将隐式Mapper作为构造函数的单独参数提供:

implicit class MapperOps1[T, D](a: T)(implicit m: Mapper[T, D]) {
  def toDto = Mapper[T, D].toDto(a)
}

The following little test compiles and outputs "42": 以下小测试编译并输出“42”:

implicit object IntToStringMapper extends Mapper[Int, String] {
  def toDto(i: Int): String = i.toString
}

import Mapper._

val s: String = 42.toDto
println(s)

Alternatively, you could try it with an implicit conversion (compiler will whine at you if you don't enable this feature explicitly, and users will whine at you if you don't use this feature wisely): 或者,你可以尝试使用隐式转换(如果你没有明确地启用这个功能,编译器会抱怨你,如果你没有明智地使用这个功能,用户会抱怨你):

class MapperOps1[T,D](a: T, mapperTD: Mapper[T, D]) {
  def toDto = {
    implicit val m: Mapper[T, D] = mapperTD
    Mapper[T,D].toDto(a)
  }
}
import scala.language.implicitConversions
implicit def wrapIntoMapperOps1[T, D]
  (a: T)
  (implicit m: Mapper[T, D]): MapperOps1[T, D] = new MapperOps1(a, m)

I won't comment on your two other attempts: apparently, the compiler cannot instantiate those, because it doesn't get enough information about the type parameters before it has to instantiate a wrapper. 我不会评论你的另外两个尝试:显然,编译器无法实例化那些,因为在必须实例化包装器之前,它没有获得有关类型参数的足够信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM