Scala多态性 - 协变和类型绑定

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala多态性 - 协变和类型绑定相关的知识,希望对你有一定的参考价值。

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

简而言之,我认为我需要类似这种类型的签名...但是如果你跟着我的虚拟例子,你会明白我为什么到这里......也许我错了。

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

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

>> error: ']' expected but identifier found

这是一个虚拟的例子,它展示了我正在尝试做的事情......我可以通过仅仅使用基本特征记录来回避这一点...但是我想让它在出于其他原因的多态性中使用真正的代码。

建立

// 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和.group看起来像是合乎逻辑的步骤......它只有100MB和100万左右的记录,所以这很好......但是如果有一个更聪明的方法从头到尾,我对这个批评持开放态度同样。

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

我是否走在正确的轨道上?

答案

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

在qazxsw poi之后你有qazxsw poi。现在,你正在做qazxsw poi,并试图传递一个函数,它需要一个.groupBy(_.k)。这不行。

想象一下,Map[String, Seq[Record]].mapValues(func)Seq[T]Record ...而AnimalT ...而现在你正试图将一堆动物传递给它,其中一些是Dogs,一些funcs,还有一些,可能是makeBark。你不能让它们全都吠叫,是吗?

你可以声明你的reducer函数接受Cat序列而不是Bird

Fish

这将编译,但似乎它对你来说似乎并不是非常有用,因为你似乎期望你的Record能够返回T def iter_2_map[T <: Record](func: Seq[Record] => T)(iter: Iterator[String]) ,而不仅仅是func(因为你之后过滤了空的) 。所以,实际上你似乎根本不需要类型参数:

EmptyRecord

以上是关于Scala多态性 - 协变和类型绑定的主要内容,如果未能解决你的问题,请参考以下文章

如何检查函数中元素的协变和逆变位置?

Typescript 中的协变和逆变

scala-协变和逆变

通用优先级队列中的协变和逆变类型

协变和逆变之疑问

协变和逆变