2010-06-08 82 views
6

尝试在Scala中使用Java地图时出现奇怪的错误。这是代码片断Scala类型转换错误,需要帮助!

val value:Double = map.get(name) 
    if (value eq null) map.put(name, time) else map.put(name, value + time) 

地图上被定义为

val map=new ConcurrentHashMap[String,Double] 

,这是我得到

error: type mismatch; 
found : Double 
required: ?{val eq: ?} 
Note that implicit conversions are not applicable because they are ambiguous: 
both method double2Double in object Predef of type (Double)java.lang.Double 
and method doubleWrapper in object Predef of type (Double)scala.runtime.RichDouble 
are possible conversion functions from Double to ?{val eq: ?} 
if (value eq null) map.put(name, time) 

错误我是新来斯卡拉所以我有一个很难分析堆栈跟踪。任何帮助,将不胜感激

回答

5

首先,map.get(name)的情况下将不会返回nullname键不存在于地图上。它将返回Double(0.0)。其次,您看到的错误是因为scala试图隐式地将返回的Double值转换为适合于eq比较的类型,并且它在范围中发现多个隐式转换。

更好的方式做你正在做的事情是

if (map contains name) map.put(name, map.get(name) + time) 
else map.put(name, time) 
+0

谢谢你的解释 – 2010-06-08 16:02:20

3
error: type mismatch; 
found : Double 
required: ?{val eq: ?} 

这里的问题是,eq仅用于扩展AnyRef类中定义,并通过Null延长,但延长Double代替AnyVal

1

正如丹尼尔写道,尝试用Double编写Java风格的部分问题来自于Scala中的Doublescala.Double而不是java.lang.Double。如果你想在风格的Java编程,你将不得不大意如下走:

// 
// a) Java style, with concurrency problem 
// 
import java.lang.{Double=>JDouble} 
import java.util.concurrent.ConcurrentHashMap 
val map = new ConcurrentHashMap[String, JDouble] 
def update(name: String, time: Double) { 
    val value: JDouble = map.get(name) 
    if (value eq null) 
    map.put(name, time) 
    else 
    map.put(name, JDouble.valueOf(value.doubleValue + time)) 
} 
update("foo", 42.0d) 
update("foo", 41.0d) 
assert(map.get("foo") == 83.0d) 

斯卡拉2.8中包含Scala的包装为ConcurrentMap S,所以你可以很容易地避免java.lang.Double问题VS scala.Double。我会保持一段时间的程序结构。

// 
// b) Scala style, with concurrency problem. 
// 
import collection.JavaConversions._ 
import collection.mutable.ConcurrentMap 
import java.util.concurrent.ConcurrentHashMap 
val map: ConcurrentMap[String, Double] = new ConcurrentHashMap[String,Double]() 
def update(name: String, time: Double) { 
    map.get(name) match { 
    case None => map.put(name, time) 
    case Some(value) => map.put(name, value + time) 
    } 
} 
update("foo", 42.0d) 
update("foo", 41.0d) 
assert(map("foo") == 83.0d) 

在变型b)中不存在表示缺少的值作为0.0D非彼java.lang.Double不与运营商和拳击发挥很好的问题既没有问题。但是,a)和b)版本对于它们的并发行为都存在疑问。 Mansoor的代码使用ConcurrentHashMap,其目的是允许同时访问地图。在原始版本的代码中,有可能在获取旧的value和存储value + time之间丢失地图更新。 以下变体c)试图避免这个问题。

// 
// c) Scala style, hopefully safe for concurrent use ;) 
// 
import collection.JavaConversions._ 
import collection.mutable.ConcurrentMap 
import java.util.concurrent.ConcurrentHashMap 
val map: ConcurrentMap[String, Double] = new ConcurrentHashMap[String,Double]() 

def update(name: String, time: Double) { 
    val valueOption: Option[Double] = map.putIfAbsent(name, time) 
    def replace(value: Double) { 
    val replaced = map.replace(name, value, value + time) 
    if (!replaced) { 
     replace(map(name)) 
    } 
    } 
    valueOption foreach { replace(_) } 
} 

update("foo", 42.0d) 
update("foo", 41.0d) 
assert(map("foo") == 83.0d)