2010-06-08 9 views
6

Me aparece un error extraño cuando intento usar un mapa de Java en Scala. Este es el fragmento de código¡Error de conversión de tipo Scala, necesita ayuda!

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

el mapa se define como

val map=new ConcurrentHashMap[String,Double] 

y este es el error que estoy recibiendo

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) 

Soy nuevo en Scala, así que estoy teniendo una Es difícil analizar el stacktrace. Cualquier ayuda sería apreciada

Respuesta

5

Primero, map.get(name) no devolverá null en el caso cuando la clave name no está presente en el mapa. En su lugar, devolverá un Double(0.0).

En segundo lugar, el error que ve es porque Scala está tratando de convertir implícitamente el valor Double devuelto a un tipo adecuado para la comparación eq y encuentra más de una conversión implícita en el ámbito.

La mejor manera de hacer lo que está haciendo es

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

Gracias por la explicación –

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

El problema aquí es que eq sólo está definido para las clases que se extienden AnyRef y extendieron por Null, pero Double extiende AnyVal lugar.

1

Como escribió Daniel, parte del problema al intentar escribir en un estilo Java con Double proviene del hecho de que Double en Scala es scala.Double y no java.lang.Double. Si usted quiere programar en el estilo de Java que tendría que ir a lo largo de las siguientes líneas:

// 
// 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 envoltorio Scala de ConcurrentMap s, lo que puede evitar fácilmente el problema de java.lang.Double vs scala.Double. Mantendré la estructura del programa por 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) 

En la variante b) anterior no es ni el problema de representar el valor que falta como 0.0d ni el problema que java.lang.Double no juega bien con los operadores y el boxeo. Pero ambas versiones a) yb) son cuestionables con respecto a su comportamiento de simultaneidad. El código de Mansoor usa un ConcurrentHashMap, que tiene el propósito de permitir el acceso concurrente al mapa. En la versión original del código existe la posibilidad de que se pierda una actualización del mapa entre obtener el antiguo value y almacenar el value + time. Variante c) a continuación trata de evitar ese 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)