在Scala中键入嵌套类型的推断

时间:2015-12-27 00:41:01

标签: scala type-inference

我想编写一个采用嵌套类型的泛型类。外部类型(I)必须扩展Iterable,内部类型(M)可以是任何东西。

以下是我的例子:

// The outer type here is I and the inner type is M
class GenericDistributor[I <: Iterable[M], M] {
  def map(input: I): Unit = {
    input.foreach(item => {
      //do some stuff
    })
  }
}

class IntegerGroup(id: Int, items: Set[Int]) extends Iterable[Int] {
  override def iterator: Iterator[Int] = items.iterator
}

object IntegerGroupDistributor extends GenericDistributor[IntegerGroup, Int]

val integerGroup = new IntegerGroup(1, Set(1,2,3))
IntegerGroupDistributor.map(integerGroup)

问题是我必须在GenericDistributor类中明确定义内部类型M,这是我不想要的。在给定外部类型的情况下,Scala有没有办法自动推断内部类型?

编辑

根据@Arioch的评论。我试过鸭子类型,这似乎解决了我的问题,但我觉得应该有更简洁的方式。

class GenericDistributor[I <: {type M; def iterator: Iterator[M]}] {
  def map(input: I): Unit = {
    val it: Iterator[M] = input.iterator
    it.foreach(println)
  }
}

class IntegerGroup(id: Int, items: Set[Int]) extends Iterable[Int] {
  type M = Int
  override def iterator: Iterator[Int] = items.iterator
}

object IntegerGroupDistributor extends GenericDistributor[IntegerGroup]

2 个答案:

答案 0 :(得分:2)

如果您不需要使用I类型的任何自定义方法,则只需在M上参数化您的外部类。 Iterator[M]不需要单独添加,因为您已经拥有了从M定义它所需的全部内容。

class GenericDistributor[M] {
   type I = Iterable[M]
   def map(input: I): Unit = {
      input.foreach(item => {
         //do some stuff
      })
   }
}

答案 1 :(得分:2)

如果您只想要一个类型参数,则有两个选项:

(1)说明你不关心迭代器的类型

class GenericDistributor[I <: Iterable[_]]

(2)使用隐式存储内部类型

class GenericDistributor[I : IterableInfo]
// or (equivalently)
class GenericDistributor[I]()(implicit i: IterableInfo[I])

trait IterableInfo[I] {
  type Element
}

object IterableInfo {
  implicit def forIterable[I <: Iterable[M], M]: IterableInfo[I] { type Element = M } = ...
}

最后一个选项允许您以多种不同方式塑造代码。您可以向IterableInfo添加方法,可以添加type个成员,可以在Iterable类型参数中添加I限制。