考虑一个类,如下所示:
import scala.collection.mutable.{HashMap => MutableHashMap}
class CustomHashMap[K,V](hashMap: MutableHashMap[K,V], initVal: V) {
def addMaps(first: MutableHashMap[K, V], second: MutableHashMap[K, V]): MutableHashMap[K, V] = {
second.foreach(pair => { first += (pair._1 -> (first.getOrElse(pair._1, initVal) + pair._2)) } )
//The above line throws a compile time error
first
}
//Other functions
}
添加两个参数化类型后,会出现编译时错误
expected (K,V) recieved (K,String)
我想知道为什么scala会做这种隐式转换?由于java中不允许运算符重载,这似乎合乎逻辑,但在scala的情况下,V实际上可能是一个可以为其定义方法
+
的类。 最佳答案
这是一种如何手动实现这种事情的方法:
由于看起来您正在尝试定义一个幺半群,我将冒昧地将 initVal
从 addMaps
移动到操作的定义中。
这可以通过 Scala 中的通用类型类模式来完成,但您必须手动定义 +
对每种类型的含义,您想在 map 中使用。
基本上你有一个特征 Monoid
:
trait Monoid[T] {
def mzero: T // your initVal
def madd(first: T, second: T): T // the + operation
}
比您为扩展该特征的每种类型定义隐式实现。您可以在
Monoid
的伴生对象,会自动使用,下面是一个
Monoid
伴随对象的例子,它定义了字符串和各种数字的实现:object Monoid {
implicit object StringMonoid extends Monoid[String] {
def mzero = ""
def madd(first: String, second: String) = first + second
}
implicit def NumericMonoid[T](implicit ev: Numeric[T]): Monoid[T] =
new Monoid[T] {
import Numeric.Implicits._
def mzero = ev.zero
def madd(first: T, second: T) = first + second
}
}
然后在您的
addMaps
函数请求映射的元素应该是 Monoid
s,并使用由 monoid 实现对元素提供的操作:def addMaps[K, V](first: MutableHashMap[K, V], second: MutableHashMap[K, V])
(implicit ev: Monoid[V]): MutableHashMap[K, V] = {
second.foreach { pair =>
first += (pair._1 -> ev.madd(first.getOrElse(pair._1, ev.mzero), pair._2)) }
first
}
这是一个测试它是如何工作的:
scala> addMaps(MutableHashMap(1 -> 2, 3 -> 4), MutableHashMap(1 -> 3, 5 -> 7))
res1: scala.collection.mutable.HashMap[Int,Int] = Map(5 -> 7, 1 -> 5, 3 -> 4)
scala> addMaps(MutableHashMap(1 -> "foo", 2 -> "bar"), MutableHashMap(1 -> "baz", 3 -> "qoo"))
res2: scala.collection.mutable.HashMap[Int,String] = Map(2 -> bar, 1 -> foobaz, 3 -> qoo)
关于java - 为什么scala中参数化类型的+运算符总是导致字符串,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30820261/