2010-06-08 14 views
6

Viene visualizzato un errore strano quando si tenta di utilizzare una mappa Java in Scala. Questo è il frammento di codiceErrore di conversione del tipo Scala, serve aiuto!

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

la mappa è definito come

val map=new ConcurrentHashMap[String,Double] 

e questo è l'errore che sto ottenendo

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) 

Sono nuovo di Scala così io sto avendo un tempo difficile analizzando lo stacktrace. Qualsiasi aiuto sarebbe gradito

risposta

5

Primo, map.get(name) non restituirà null nel caso in cui la chiave name non sia presente nella mappa. Restituirà invece un Double(0.0).

In secondo luogo, l'errore visualizzato è perché scala sta tentando di convertire implicitamente il valore Double restituito in un tipo adatto per la comparazione eq e trova più di una conversione implicita nell'ambito.

Il modo migliore per fare ciò che si sta facendo è

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

Grazie per la spiegazione –

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

Il problema qui è che eq è definito solo per le classi estendono AnyRef e prorogato di Null, ma Double estende AnyVal invece.

1

Come ha scritto Daniel, parte del problema che si prova a scrivere in uno stile Java con Double deriva dal fatto che Double in Scala è scala.Double e non java.lang.Double. Se si voleva programmare in stile Java si dovrebbe andare secondo le seguenti linee:

// 
// 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) 

Scala 2.8 contiene un wrapper Scala per ConcurrentMap s, in modo da poter facilmente evitare il problema di java.lang.Double vs scala.Double. Terrò la struttura del programma per un momento.

// 
// 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) 

In variante b) di cui sopra v'è né il problema di rappresentare il valore mancante come 0.0d né il problema che java.lang.Double non gioca bene con operatori e boxe. Ma entrambe le versioni a) eb) sono discutibili riguardo al loro comportamento concorrente. Il codice di Mansoor utilizza uno ConcurrentHashMap, che ha lo scopo di consentire l'accesso simultaneo alla mappa. Nella versione originale del codice c'è la possibilità che venga perso un aggiornamento della mappa tra il recupero del vecchio value e l'archiviazione di value + time. La variante c) sotto cerca di evitare questo problema.

// 
// 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) 
Problemi correlati