2010-03-17 14 views

Respuesta

3

Hay una read only projection de mapas mutables

scala> collection.mutable.Map(1->2).readOnly 
res0: scala.collection.Map[Int,Int] = ro-Map(1 -> 2) 

Como oxbow_lakes pointed out el Mapa subyacente todavía es mutable y puede cambiar después de la proyección de sólo lectura se publica a los clientes. La ilusión de inmutabilidad tiene que abordarse en el código que gestiona el mapa.

+5

Parece que se trata de un método 2.7. Está comentado en 2.8.0-Beta1 y los documentos nocturnos no lo muestran. – IttayD

+2

esto parece obsoleto, use 'collection.mutable.Map (1-> 2) .toMap' – Mermoz

+1

Desafortunadamente,' toMap' copia las entradas del mapa. Creo que estamos buscando algo que simplemente envuelva el mapa con una interfaz inmutable. – Mike

3

Lo que está pidiendo es inherentemente inseguro. Puede pasar el mutable.Map alrededor como collection.Map que es inmutable pero los "clientes" que utilizan este formulario no pueden estar seguros de que su vista no cambiará desde debajo de ellos.

+0

Tu punto es válido. El mapa de solo lectura solo funcionará si el Mapa subyacente no se cambia después de que los clientes lo hayan referenciado. El uso no es seguro es este respeto. Esto es una compensación y no será un gran problema para los casos de uso real, siempre y cuando publique solo la proyección de solo lectura como lo haría con java.util.Collections.unmodifiableMap. –

+0

Me parece que utilizo Java 'unmodifiableXyz' cuando deseo pasar alguna colección inicializada fuera de la clase que * posee * it. Es decir que hago esto en los casos en que puedo estar seguro de que los datos no cambiarán desde debajo de un lector, solo deseo asegurarme de que un lector no pueda modificarlo. Mi solución anterior es, por lo tanto, inadecuada. Creo que –

6

Como Thomas señala, la vista de solo lectura es O (1). Pero solo lectura no equivale a inmutabilidad.

La diferencia es bien descrived en el documento "Fighting Bit Rot":

Todas las clases de colección se mantienen en un scala.collection paquete. Este paquete tiene tres subpaquetes: mutable, inmutable y genérico. La mayoría de las colecciones existen en tres formas, , dependiendo de su mutabilidad.

Una colección en el paquete scala.collection.immutable es garantiza que sea inmutable para todos. Eso significa que uno puede confiar en el hecho de que acceder al mismo valor de colección a lo largo del tiempo siempre dará una colección con los mismos elementos . Se conoce una colección en el paquete scala.collection.mutable en que tiene algunas operaciones que cambian la colección en su lugar.

Una colección en el paquete scala.collection puede ser mutable o inmutable. Por ejemplo, collection.Seq [T] es una superclase de collection.immutable.Seq [T] y collection.mutable.Seq [T]. Generalmente, las colecciones de raíz en el paquete scala. colección definir la misma interfaz como las colecciones inmutables, y las colecciones mutables en paquete scala.collection.mutable suelen añadir algunos destructivos de modificación operaciones a esta interfaz inmutable . La diferencia entre colecciones de raíz y inmutables colecciones es que un usuario de una colección inmutable tiene una garantía que nadie puede mutar la colección, mientras que los usuarios de las colecciones de raíces tienen suponer modificaciones por otros, a pesar de que no se puede hacer cualquier modificación ellos mismos.

Tal vez es simplemente un simple como el lanzamiento de nuevo.

scala> val mm = collection.mutable.Map(1 -> 2) 
mm: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2) 

scala> val readOnly = mm : collection.Map[Int, Int] 
readOnly: scala.collection.Map[Int,Int] = Map(1 -> 2) 
+2

La diferencia entre el casting y el map.readOnly es que el usuario puede lanzar collection.Maps a un mapa mutable o usar reflection para cambiar el mapa. –

+0

Buen punto. Parece que la solución 2.8 para esto podría estar usando 'MapProxy', pero no puedo envolver fácilmente un' collection.MapProxy' alrededor de un 'colletion.mutable.Map' todavía. por ejemplo 'val mm = collection.mutable.Map (1 -> 2); nueva colección.MapProxy [Int, Int] {val self = mm} ' – retronym

+0

' MapProxy' ahora está en desuso a partir del 2.11. – Mike

3

En principio, se podría agregar un método de "congelación" a una estructura de datos mutable que evite más mutaciones. Esta es la única forma incluso ligeramente segura de realizar la envoltura. (Solo un poco porque después de eso tendrías que lanzar excepciones cuando intentaste mutarlo). Las colecciones mutables de Scala no tienen esta capacidad, sin embargo. Se podría agregar a, p. mutable.HashMap anulando todos los métodos de mutación (update, +=, ++=, etc.), pero esto sería un poco de trabajo.

2

El trabajo de Philipp Haller en Capabilities for Uniqueness and Borrowing está relacionado con esto. Hay muchos otros trabajos en el dominio de imponer la "propiedad" a través del sistema de tipos, pero Philipp realmente proporciona un complemento utilizable para el compilador de Scala.