2010-06-08 83 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)