2010-03-17 11 views

risposta

3

C'è una read only projection per mappe mutevoli

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

Come oxbow_lakes pointed out sottostante mappa è ancora mutevole e potrebbe cambiare dopo la sola lettura di proiezione viene pubblicato ai clienti. L'illusione dell'immutabilità deve essere affrontata nel codice che gestisce la mappa.

+5

Sembra che questo sia un metodo 2.7. È commentato in 2.8.0-Beta1 e i documenti notturni non lo mostrano. – IttayD

+2

sembra deprecato, usa 'collection.mutable.Map (1-> 2) .toMap' – Mermoz

+1

Sfortunatamente,' toMap' copia le voci della mappa. Penso che stiamo cercando qualcosa che avvolga la mappa con un'interfaccia immutabile. – Mike

3

Quello che chiedi è intrinsecamente pericoloso. Puoi passare lo mutable.Map in giro come collection.Map che è immutabile ma i "client" che utilizzano questo modulo non possono essere sicuri che la loro vista non cambierà da sotto di essi.

+0

Il tuo punto è valido. La mappa di sola lettura funziona solo se la mappa sottostante non viene modificata dopo che i client hanno ricevuto un riferimento. L'utilizzo non è sicuro è questo rispetto. Questo è un compromesso e non sarà un grosso problema per i casi di utilizzo reale, purché tu pubblichi solo la proiezione di sola lettura, proprio come tu utilizzi java.util.Collections.unmodifiableMap. –

+0

Trovo che io usi Java 'unmodifiableXyz' quando desidero passare qualche raccolta inizializzata al di fuori della classe che * possiede * it. Questo per dire che lo faccio nei casi in cui posso essere sicuro che i dati non cambieranno da sotto un lettore, desidero solo assicurarmi che un lettore non possa modificarlo. La mia soluzione sopra è quindi inadatta Penso che –

6

Come osserva Thomas, la vista di sola lettura è O (1). Ma la sola lettura non equivale a immutabilità.

La differenza è ben descrived nel "Fighting Bit Rot" carta:

Tutte le classi di raccolta sono conservati in un pacchetto scala.collection. Questo pacchetto ha tre sotto-pacchetti: modificabile, immutabile e generico. La maggior parte delle raccolte esiste in tre forme, a seconda della loro mutevolezza.

Una raccolta nel pacchetto scala.collection.immutable è garantita per essere immutabile per tutti. Ciò significa che ci si può affidare a per il fatto che l'accesso allo stesso valore di raccolta nel tempo corrisponderà sempre a e produce una raccolta con gli stessi elementi . Una collezione nel pacchetto scala.collection.mutable è nota a con alcune operazioni che modificano la raccolta in posizione.

Una raccolta nel pacchetto scala.collection può essere mutabile o immutabile. Ad esempio, la collezione .Seq [T] è una superclasse di entrambi collection.immutable.Seq [T] e collection.mutable.Seq [T]. Generalmente, le raccolte radice nel pacchetto scala. raccolta definire la stessa interfaccia le collezioni immutabili, e le collezioni mutabili nel pacchetto scala.collection.mutable tipicamente inserirlo alcuni distruttivi modifica operazioni di questa immutabile interfaccia . La differenza tra collezioni radice e immutabili collezioni è che un utente di una collezione immutabile ha una garanzia che nessuno può mutare la raccolta, mentre gli utenti di collezioni radice hanno assumere modifiche da altri, anche se non possono fare eventuali modifiche allo .

Forse è solo un semplice come up-casting.in linea di principio

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 differenza tra casting e map.readSolo è che l'utente può lanciare collection.Map su una mappa mutabile o usare reflection per cambiare la mappa. –

+0

Buon punto. Sembra che la soluzione 2.8 di questo possa usare 'MapProxy', ma non riesco a racchiudere facilmente' collection.MapProxy 'attorno a 'colletion.mutable.Map'. ad esempio 'val mm = collection.mutable.Map (1 -> 2); nuova collezione.MapProxy [Int, Int] {val self = mm} ' – retronym

+0

' MapProxy' è ora deprecato a partire da 2.11. – Mike

3

Si potrebbe aggiungere un metodo di "congelare" per una struttura di dati mutabile che impediva un'ulteriore mutazione. Questo è l'unico modo anche poco sicuro per eseguire il wrapping. (Solo leggermente perché dopo di ciò dovresti generare eccezioni quando provi a mutarlo.) Le collezioni mutabili di Scala non hanno questa capacità, comunque. Si potrebbe aggiungere ad es. mutable.HashMap sovrascrivendo tutti i metodi di muting (update, +=, ++=, ecc.), ma questo sarebbe un bel po 'di lavoro.

2

I lavori di Philipp Haller su Capabilities for Uniqueness and Borrowing sono correlati a questo. C'è un sacco di altri lavori nel dominio dell'applicazione della "proprietà" attraverso il sistema dei tipi, ma Philipp in realtà fornisce un plugin utilizzabile al compilatore Scala.