【问题标题】:Scala Typeclasses with generics具有泛型的 Scala 类型类
【发布时间】:2015-07-09 03:06:43
【问题描述】:

我一直在使用 Scala 中的类型类模式,但我无法弄清楚当我使用的类型是泛型时如何实现隐式伴随对象。

例如,假设我为一个类型类定义了一个特征,它提供了将事物放入Boxes 的函数。

case class Box[A](value: A)

trait Boxer[A] {
  def box(instance: A): Box[A]
  def unbox(box: Box[A]): A
}

implicit object IntBoxer extends Boxer[Int] {
  def box(instance: Int) = Box(instance)
  def unbox(box: Box[Int]) = box.value
}

def box[A : Boxer](value: A) = implicitly[Boxer[A]].box(value)
def unbox[A : Boxer](box: Box[A]) = implicitly[Boxer[A]].unbox(box)

这按预期工作,允许我为各种类型提供Boxer 的实现。但是,当我希望操作的类型本身是泛型时,我知道如何执行此操作。假设我希望能够在任何Seq[A] 上使用我的Boxer。 Scala 中的objects 不能包含类型参数,所以我不知道该去哪里:

// Will not compile - object cannot have type arguments
implicit object SeqBoxer[A] extends Boxer[Seq[A]] { ... }

// Will not compile - 'A' is unrecognized
implicit object SeqBoxer extends Boxer[Seq[A]] { ... }

// Compiles but fails on execution, as this doesn't implement an implicit
// conversion for _specific_ instances of Seq
implicit object SeqBoxer extends Boxer[Seq[_]] {
  def box(instance: Seq[_]) = Box(instance)
  def unbox(box: Box[Seq[_]]) = box.value
}

// Will not compile - doesn't technically implement Boxer[Seq[_]]
implicit object SeqBoxer extends Boxer[Seq[_]] {
  def box[A](instance: Seq[A]) = Box(instance)
  def unbox[A](box: Box[Seq[A]]) = box.value
}

// Compiles, but won't resolve with 'implicitly[Boxer[Seq[Foo]]]'
// I had high hopes for this one, too :(
implicit def seqBoxer[A]() = new Boxer[Seq[A]] {
  def box(instance: Seq[A]) = Box(instance)
  def unbox(box: Box[Seq[A]]) = box.value
}

有没有什么方法可以支持泛型类型的隐式转换,而不必为每个内部类型隐式单独的对象?

【问题讨论】:

    标签: scala generics implicit-conversion typeclass implicit


    【解决方案1】:

    实际上,你真的很亲密。您需要从seqBoxer[A] 中删除括号。否则,编译器会将其视为来自() => Boxer[Seq[A]] 的隐式转换,而不是简单的可用隐式Boxer[Seq[A]]。为了更好地衡量,明确隐式方法的返回类型也是一个好主意。

    implicit def seqBoxer[A]: Boxer[Seq[A]] = new Boxer[Seq[A]] {
      def box(instance: Seq[A]) = Box(instance)
      def unbox(box: Box[Seq[A]]) = box.value
    }
    
    scala> box(Seq(1, 2, 3))
    res16: Box[Seq[Int]] = Box(List(1, 2, 3))
    

    您实际上可以使用相同的方法为任何A 创建一个通用的Boxer[A],应该要求其行为方式相同。

    implicit def boxer[A]: Boxer[A] = new Boxer[A] {
        def box(instance: A): Box[A] = Box(instance)
        def unbox(box: Box[A]): A = box.value
    }
    
    scala> box("abc")
    res19: Box[String] = Box(abc)
    
    scala> box(List(1, 2, 3))
    res20: Box[List[Int]] = Box(List(1, 2, 3))
    
    scala> unbox(res20)
    res22: List[Int] = List(1, 2, 3)
    
    scala> box(false)
    res23: Box[Boolean] = Box(false)
    

    【讨论】:

    • 啊!我完全忘记了def foo: Adef foo(): A 之间的区别。这真的很清楚!
    猜你喜欢
    • 2020-03-27
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 2019-02-02
    • 2021-08-22
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    相关资源
    最近更新 更多