在特征和方法中实现泛型

Implement generics in trait and method

我已经在 scala 用户论坛上发布了这个问题,

https://groups.google.com/forum/#!topic/scala-user/xlr7KmlWdWI

我收到了一个令我满意的答复。但是,与此同时,我想确定这是否是唯一的结论。谢谢

我的问题是,我有,

trait Combinable[A] {
  def join[B](l: List[A]): B
}

例如,当我使用 A 作为 String 和 B 作为 Int 实现此特征时,

class CombineString extends Combinable[String] {
  override def join[Int](strings: List[String]) = string.size
}

显然,Int,在 join 方法旁边,不是 Scala 整数 class 和 编译此代码将失败。或者,我可以将我的特征重写为

trait Combinable[A, B] {
  def join(l: List[A]): B
}

trait Combinable[A] {
  def join[B](l: List[A])(f: List[A] => B): B
}

我的问题是,如何按原样实现第一个示例中定义的特征?如果第一个例子因为它的定义方式而没有实际用途,为什么编译器不抱怨?再次感谢。

My question is, how can I implement the trait as defined in the first example as it is?

class CombineString extends Combinable[String] {
  override def join[B](strings: List[String]) = null.asInstanceOf[B]
  // or, for that matter, anything and then .asInstanceOf[B]
}

编译器怎么知道这不是你想要的?

您不能指望编译器理解哪些类型组合对您有意义,但您可以根据多参数隐式将这种意义指定为类型之间的关系。

结果基本上是您拒绝的两种方法的组合,但具有所需的语法。

两个被拒绝的形式中的第一个成为隐式类型:

trait Combine[A, B] {
  def apply(l: List[A]): B
}

接下来您可以定义适当的类型组合及其含义

implicit object CombineStrings extends Combine[String, String] {
  def apply(l: List[String]) = l.mkString
}

implicit object CombineInts extends Combine[Int, Int] {
  def apply(l: List[Int]) = l.sum
}

implicit object CombinableIntAsString extends Combine[Int, String] {
  def apply(l: List[Int]) = l.mkString(",")
}

最后我们修改了第二个被拒绝的表单,它隐藏了隐式结果的 f 参数:

trait Combinable[A] {
  def join[B](l: List[A])(implicit combine: Combine[A, B]): B = combine(l)
}

现在你可以定义

val a = new Combinable[String] {}
val b = new Combinable[Int] {}

并检查

a.join[String](List("a", "b", "c"))
b.join[Int](List(1, 2, 3))
b.join[String](List(1, 2, 3))

运行良好,而

a.join[Int](List("a", "b", "c"))

让编译器哭泣,直到你能提供 StringInt 之间关系的隐含值

的实际使用证据