Scala 多态性 - 协变和类型绑定
Scala polymorphism - covariant and type bound
使用 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 出现......我最终需要得到它到地图中,所以 .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
我走在正确的轨道上吗?
您使用的 +
不正确。它仅与 classes 的类型参数一起使用,以表示 class 在其参数中应该是协变的。
将它与方法一起使用没有多大意义(Seq[T]
实际上 是 Seq[Record]
的子 class - 因为 Seq
是协变的,但这对你没有帮助,因为 functions 在它们的参数类型中是 contravariant,所以 Function[Seq[T], T]
是 superclass of Function[Seq[Record], T]
,不是 subclass)。原因如下:
在 .groupBy(_.k)
之后你有 Map[String, Seq[Record]]
。
现在,您正在对它执行 .mapValues(func)
,并试图将一个函数传递给它,该函数需要一个 Seq[T]
。这行不通。
想象一下,Record
是 Animal
,T
是 Dog
...,func
是 makeBark
...现在你正试图将一堆动物传递给它,其中一些是 Cat
,一些是 Bird
,还有一些,可能是 Fish
。你总不能让它们都叫起来吧?
您可以声明您的 reducer 函数接受 Record
序列而不是 T
:
def iter_2_map[T <: Record](func: Seq[Record] => T)(iter: Iterator[String])
这会编译,但无论如何它似乎对您来说都不是很有用,因为您似乎期望您的func
能够return EmptyRecord
和 ValidRecord
,而不仅仅是 T
(因为您之后要过滤掉空的)。所以,实际上你根本不需要类型参数:
def iter_2_map(func: Seq[Record] => Record)(iter: Iterator[String])
使用 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 出现......我最终需要得到它到地图中,所以 .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
我走在正确的轨道上吗?
您使用的 +
不正确。它仅与 classes 的类型参数一起使用,以表示 class 在其参数中应该是协变的。
将它与方法一起使用没有多大意义(Seq[T]
实际上 是 Seq[Record]
的子 class - 因为 Seq
是协变的,但这对你没有帮助,因为 functions 在它们的参数类型中是 contravariant,所以 Function[Seq[T], T]
是 superclass of Function[Seq[Record], T]
,不是 subclass)。原因如下:
在 .groupBy(_.k)
之后你有 Map[String, Seq[Record]]
。
现在,您正在对它执行 .mapValues(func)
,并试图将一个函数传递给它,该函数需要一个 Seq[T]
。这行不通。
想象一下,Record
是 Animal
,T
是 Dog
...,func
是 makeBark
...现在你正试图将一堆动物传递给它,其中一些是 Cat
,一些是 Bird
,还有一些,可能是 Fish
。你总不能让它们都叫起来吧?
您可以声明您的 reducer 函数接受 Record
序列而不是 T
:
def iter_2_map[T <: Record](func: Seq[Record] => T)(iter: Iterator[String])
这会编译,但无论如何它似乎对您来说都不是很有用,因为您似乎期望您的func
能够return EmptyRecord
和 ValidRecord
,而不仅仅是 T
(因为您之后要过滤掉空的)。所以,实际上你根本不需要类型参数:
def iter_2_map(func: Seq[Record] => Record)(iter: Iterator[String])