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

问题描述 投票:1回答:1

通常的做法是提供一个帮助值类来访问类型类 - 比如

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"
    }
}

在我的例子中,我有一个带有2个参数的类型。我无法让值类工作(MapperOps)。我一直在“找不到参数映射器的隐含值”

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)
   }
}
scala typeclass
1个回答
3
投票

请注意中的重要区别

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

你有这个A : Show部分,基本上是自省

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

由于双参数“Type-Pair-Classes”没有简洁的[T : MyTypeClass]语法,因此必须将隐式Mapper作为单独的参数提供给构造函数:

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

以下小测试编译并输出“42”:

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

import Mapper._

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

或者,你可以尝试使用隐式转换(如果你没有明确地启用这个功能,编译器会抱怨你,如果你没有明智地使用这个功能,用户会抱怨你):

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)

我不会评论你的另外两个尝试:显然,编译器无法实例化那些,因为在必须实例化包装器之前,它没有获得有关类型参数的足够信息。

© www.soinside.com 2019 - 2024. All rights reserved.