scala - scala中的嵌套多态性
问题描述
我需要一个带有方法的隐式类,它可以让我合并任何<: Map
可能具有重复键和多态值的不可变映射类型 ()。我无法弄清楚让隐式类使用嵌套的多态类型并隐式工作(类似于A <: Map[_, B], B <: Combinable[B]
)。
我可以让它适用于所有 Map 类型......或多态值......但不能同时适用。我无法弄清楚如何组合成一个隐式类而不会出现在隐式类中找不到方法的错误。
所以例如...
trait Combinable[A] {
this: A =>
def combine(that: A): A
def combine(that: Option[A]): A = that match {
case Some(a) => this combine a
case None => this
}
}
所以假设我有一堂课......
case class Meta(???) extends Combinable[Meta] {
def combine(that: Meta): Meta = ???
}
现在,如果我有一个标准Map
的 immutable ,那就很简单了……效果很好。
implicit class CombinableMaps[A <: Combinable[A]](val m1: Map[String, A]) {
def mergeMaps(m2: Map[String, A]): Map[String, A] = {
m1 ++
m2.map { case (k,v) => k -> (v combine m1.get(k)) }
}.asInstanceOf[Map[String, A]]
}
但是,如果我希望它也适用于TreeMap
s 和SortedMap
s 以及其他任何东西怎么办?
implicit class CombinableMaps[B <: Combinable[B], A <: Map[String,B]](val m1: A) {
def mergeMaps(m2: A): A = {
m1 ++
m2.map { case (k,v) => k -> (v combine m1.get(k)) }
}.asInstanceOf[A]
}
这编译没有错误,但是当我尝试使用mergeMap
它抛出的方法时error: value mergeMaps is not a member of Map[String,Meta]
。
我尝试了一种变体,其中B
将类型传递给A
like A[B]
... 再次编译(如果我导入scala.language.higherKinds
了)但没有被应用。
这种嵌套多态是否允许?我什至无法弄清楚要搜索什么词。
提前致谢。
解决方案
解决问题的关键是不要试图A
立即推断。即使是简单的事情也会导致类型推断:
class Foo[B, A <: Map[String, B]](val a: A)
new Foo(Map("foo" -> 42))
inferred type arguments [Nothing,scala.collection.immutable.Map[String,Int]] do not conform to value 's type parameter bounds [B,A <: Map[String,B]]
type mismatch;
found : scala.collection.immutable.Map[String,Int]
required: A
这是因为类型推断在“层”中起作用:它A
在B
检查A
. 解决方案是对 A 进行不同的定义:
class Foo[B, A[X] <: Map[String, X]](val a: A[B])
new Foo(Map("foo" -> 42))
现在让我们看看你的问题。您的Combinable
trait 通常会被类型类替换,这样您就不必扩展您需要组合Combinable
的每种类型。A
您可以隐Combinable
式地为您需要的每种类型提供隐式。这完全是可选的,如果你愿意,你可以选择坚持你的特质。
trait Combinable[A] {
def combine(first: A, second: A): A
def combine(first: A, second: Option[A]): A = second match {
case Some(a) => combine(first, a)
case None => first
}
}
case class Meta(x: Int)
object Meta {
implicit val combinableInstance: Combinable[Meta] = (first, second) => Meta(first.x + second.x)
}
implicit class CombinableMaps[B : Combinable, A[X] <: Map[String,X]](val m1: A[B]) {
def mergeMaps(m2: A[B]): A[B] = {
m1 ++
m2.map { case (k,v) => k -> implicitly[Combinable[B]].combine(v,m1.get(k)) }
}.asInstanceOf[A[B]]
}
import collection.immutable.TreeMap
val m = TreeMap("foo" -> Meta(42), "bar" -> Meta(43))
val m2 = TreeMap("bar" -> Meta(43))
val m3: TreeMap[String,Meta] = m.mergeMaps(m2)
推荐阅读
- ios - 计算2个日期的百分比差异
- html - 如何在不丢失边框的情况下对齐网格行和网格列内的文本?
- javascript - 进行评估的可能方法
- c - 为什么我的函数没有被调用?我不明白为什么需要声明
- twilio - 是否可以仅在 IIS 上运行 Twilio Video 并用 C# 编写?
- c# - Directory.CreateDirectory 导致 System.IO 错误文件写入太快
- python-3.x - SAWarning:评估非映射列表达式
- vba - 使用 VBA 在工作表中搜索单词组合
- android - 将收到的通知存储在我的 Android 应用程序中?
- javascript - 调用javascript方法变量丢失'this'