1

使用 Scala ...我无法弄清楚如何以混合类型绑定和协变的方式使用多态性。

简而言之,我认为我需要类似这种类型签名的东西......但是如果你按照我的虚拟示例进行操作,你就会明白我为什么会来到这里......也许我错了。

def func[+T <: U](func: Seq[T] => T)(iter: Iterator[String]): Map[String, String] = ???

但这种方法会产生......

>> error: ']' expected but identifier found

这是一个虚拟示例,它演示了我正在尝试做的事情...我可以通过仅使用基本特征 Record 来回避这个问题...但我想让它与出于其他原因的多态性一起工作真正的代码。

设置

// underlying trait to hold key and value
trait Record {
  def k: String 
  def v: String
  def isDefined: Boolean
}

// companion object with apply method
object Record {
  def apply(s: String): Record = s.split(",") match {
    case Array(k,v) => new ValidRecord(k,v).asInstanceOf[Record]
    case _          => EmptyRecord.asInstanceOf[Record]
  }
}

// singleton for empty records
object EmptyRecord extends Record {
  val k = ""
  val v = ""
  val isDefined = false
}

// class for actual data
class ValidRecord(val k: String, val v: String) extends Record {
  val isDefined = true
}

多态函数

注意 - 从 Iterator 到 Seq 这里看起来有问题......我正在从 src/main/resources 读取一个文件......它作为一个 Iterator 进来......我最终需要将它放入一个 Map 中,所以.toSeq 和 .groupBy 似乎是合乎逻辑的步骤......它可能只有 100MB 和一百万左右的记录,所以这很好用......但如果有更聪明的方式来从头到尾,我愿意接受批评也是。

def iter_2_map[T <: Record](func: Seq[T] => T)(iter: Iterator[String]): Map[String, String] = {
  iter                               // iterator of raw data
  .map(Record.apply)                 // Iterator[Record]
  .toSeq                             // gives .groupBy() method
  .groupBy(_.k)                      // Map[k -> Seq[Record]]; one Seq of records per k
  .mapValues(func) // <<< ERROR HERE //function to reduce Seq[Record] to 1 Record
  .filter(_._2.isDefined)            // get rid of empty results
  .mapValues(_.v)                    // target of Map is just v
}

错误

found   : Seq[T] => T
required: Seq[Record] => ?
          .mapValues(func)
                     ^

如果我分解所有这些步骤并在每个相关步骤中声明类型...错误会更改为此...

found   : Seq[T] => T
required: Seq[Record] => Record
          .mapValues(func)
                     ^

所以这就是我难过的地方。我认为使 T 协变解决了这个问题...... T 是 Record 的声明子类型,但也许它没有将 Seq[T] 识别为 <: Seq[Record]?

但是进行此更改会在顶部产生错误...

def iter_2_map[+T <% Record](func: Seq[T] => T)(iter: Iterator[String]): Map[String, String] = {
  ???
}

回到这个...

>> error: ']' expected but identifier found

我什至走在正确的轨道上吗?

4

1 回答 1

2

您使用+不正确。它仅与类的类型参数一起使用,表明该类的参数应该是协变的。将它与方法一起使用没有多大意义(Seq[T]实际上-的子类,Seq[Record]因为Seq它是协变的,但这对您没有帮助,因为函数的参数类型是逆变Function[Seq[T], T]的,所以是 的超类Function[Seq[Record], T]而不是子类)。原因如下:

.groupBy(_.k)你拥有Map[String, Seq[Record]]. 现在,您正在.mapValues(func)处理它,并尝试将一个函数传递给它,该函数需要一个Seq[T]. 这行不通。

想象一下,Record就是Animal, 并且TDog... 并且funcmakeBark... 现在你正试图将一堆动物传递给它,其中一些是Cats,一些Bird是 s,还有一些,也许是Fish。你不能让它们都吠叫,对吗?

你可以只声明你的 reducer 函数来接受Record序列,而不是T

   def iter_2_map[T <: Record](func: Seq[Record] => T)(iter: Iterator[String])

这将编译,但无论如何它似乎对您不是很有用,因为您似乎希望func能够同时返回and EmptyRecordValidRecord而不仅仅是T(因为您之后要过滤空)。因此,实际上您似乎根本不需要类型参数:

  def iter_2_map(func: Seq[Record] => Record)(iter: Iterator[String])
于 2017-12-19T02:39:02.540 回答