繁体   English   中英

在Scala中使用类型类的隐式参数类型

[英]Using Parametric Type in Implicit for Type Classes in Scala

我想了解更多关于Scala中TypeClasses的知识 ,并提出了这个例子

trait Cons[T] {
    def cons(t1: T, t2: T):T
}

object Cons {
    implicit object StringCons extends Cons[String] {
        override def cons(t1: String, t2: String): String = t1 + t2
    }

    implicit object ListCons extends Cons[List[_]] {
        override def cons(t1: List[_], t2: List[_]): List[_] = t1 ++ t2
    }

    implicit object IntCons extends Cons[Int] {
        override def cons(t1: Int, t2: Int): Int = Integer.parseInt(t1.toString + t2.toString)
    }
}

def Cons[T](t1: T, t2: T)(implicit c: Cons[T]):T = {
    c.cons(t1, t2)
}

Cons("abc", "def") // abcdef
Cons(1, 2) // 12
Cons(List(1,2,3),List(4,5,6)) // does not work, as the expected type is List[Int]

当我创建ListCons我明确地设置了List[_]的类型,如果我理解正确的是存在类型并且等同于Java通配符,这意味着它是某种类型而我们并不关心。

现在问题是为什么这不起作用。 有没有办法让它发挥作用。 或者也许我有一些根本的误解。

Cons(List(1,2,3),List(4,5,6))不起作用的原因是因为通过类型推断规则它意味着Cons[List[Int]](List[Int](1,2,3), List[Int](4,5,6)) ,所以它特别需要一个隐含的Cons[List[Int]] ,而Cons[List[_]]不是Cons[List[Int]]

Cons[List[_]] Cons[List[Int]]如果Cons是逆变的(声明为Cons[-T] ),但它不能逆变,因为它有一个返回T的方法(除非你作弊@uncheckedVariance ,你不应该)。

使其工作的正确方法是用ListCons替换ListCons

implicit def listCons[T]: Cons[List[T]] = new Cons[List[T]] {
    override def cons(t1: List[T], t2: List[T]): List[T] = t1 ++ t2
}

我添加了更高级的kinded类型,这将使​​您能够捕获您的类型:

这是我的尝试:

trait Cons[T] {
  def cons(t1: T, t2: T): T
}

trait HigherKindCons[M[_]] {
  def cons[T](t1: M[T], t2: M[T]): M[T]
}

object Cons {
  implicit object StringCons extends Cons[String] {
    override def cons(t1: String, t2: String): String = t1 + t2
  }

  implicit object ListCons extends HigherKindCons[List] {
    override def cons[T](t1: List[T], t2: List[T]): List[T] = t1 ++ t2
  }

  implicit object OptCons extends HigherKindCons[Option] {
    override def cons[T](t1: Option[T], t2: Option[T]): Option[T] = t1 orElse t2
  }

  implicit object IntCons extends Cons[Int] {
    override def cons(t1: Int, t2: Int): Int =  Integer.parseInt(t1.toString + t2.toString)
  }
}


import Cons._

def Cons[T](t1: T, t2: T)(implicit c: Cons[T]):T = {
  c.cons(t1, t2)
}

def Cons[T, M[_]](t1: M[T], t2: M[T])(implicit c: HigherKindCons[M]): M[T] = {
  c.cons(t1, t2)
}


Cons[String]("abc", "def") // abcdef
Cons(1, 2) // 12
Cons(List(1,2,3),List(4,5,6))
Cons(List("a", "b"),List("c", "d", "e")) // as the expected type is List[String]
Cons(Some(1), None)

输出:

res0: String = abcdef
res1: Int = 12
res2: List[Int] = List(1, 2, 3, 4, 5, 6)
res3: List[String] = List(a, b, c, d, e)
res4: Option[Int] = Some(1)

暂无
暂无

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

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