使用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进入...我最终需要得到它进入地图,所以.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]识别为&lt ;: Seq [Record]?
但是进行此更改会在顶部产生错误...
def iter_2_map[+T <% Record](func: Seq[T] => T)(iter: Iterator[String]): Map[String, String] = {
???
}
回到这个......
>> error: ']' expected but identifier found
我是否在正确的轨道上?
答案 0 :(得分:2)
您错误地使用了+
。它仅与 classes 的类型参数一起使用,以表示该类在其参数中应该是协变的。
将它与方法一起使用没有多大意义(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
为T
,Dog
为func
... makeBark
为Cat
......现在你试图将一堆动物传给它,其中一些是Bird
个,一些是Fish
个,有些可能是Record
。你不能让它们全都吠叫,是吗?
你可以声明你的reducer函数接受T
序列而不是 def iter_2_map[T <: Record](func: Seq[Record] => T)(iter: Iterator[String])
:
func
这会编译,但似乎对你来说不是很有用,因为你似乎期待你的EmptyRecord
能够返回两者< / em> ValidRecord
和T
,而不仅仅是 def iter_2_map(func: Seq[Record] => Record)(iter: Iterator[String])
(因为您之后会过滤掉空白)。所以,实际上你似乎根本不需要类型参数:
"managed_image_resource_group_name": "myResourceGroup",