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

时间:2016-08-19 03:33:13

标签: scala types

我想在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通配符,这意味着它是某种类型,我们不在乎。

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

2 个答案:

答案 0 :(得分:4)

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替换为

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

答案 1 :(得分:1)

我添加了更高级的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)