2013-07-11 7 views
6

VectorBuilder è definito nello stesso file di origine Vector. Vector è immutabile e nel pacchetto scala.collections.immutable, pertanto il builder si trova nello stesso pacchetto.Perché VectorBuilder nel pacchetto scala.collections.immutable?

Per quanto posso dire, CanBuildFrom utilizza uno VectorBuilder come predefinito, se il tipo di ritorno non è tipizzato esplicitamente.

  • C'è un motivo per non avere il builder in un file separato nel pacchetto mutabile?
  • Il builder non deve essere utilizzato direttamente? In tal caso, quale builder o buffer deve essere utilizzato per creare un Seq?

risposta

3

VectorBuilder non è destinato a essere utilizzato direttamente. Se si desidera ottenere un costruttore per un Vector, è sufficiente chiamare lo Vector.newBuilder[T], che restituisce un Builder[T, Vector[T]] (con l'istanza sottostante è un VectorBuilder).

Quindi, se si desidera che il costruttore di default che sarebbe stato utilizzato per creare un Seq, avete solo bisogno di chiamare Seq.newBuilder:

scala> Seq(1,2,3) 
res0: Seq[Int] = List(1, 2, 3) 

scala> Seq.newBuilder[Int] 
res1: scala.collection.mutable.Builder[Int,Seq[Int]] = ListBuffer() 

scala> Seq.newBuilder[Int].result 
res2: Seq[Int] = List() 

Quanto sopra dimostra che l'implementazione predefinita di Seq è la lista, e, logicamente, il builder predefinito per un Seq è in realtà un mutable.ListBuffer.

ListBuffer è più di un semplice List costruttore, è per questo che è in collection.mutable mentre VectorBuilder non è un Buffer, non può essere utilizzato per altro che costruire un Vector. Questo è probabilmente il motivo per cui è definito localmente in Vector. Non sono sicuro del motivo per cui non è private, non riesco a vederlo referenziato in nessuna parte dell'API pubblica di Vector stesso. Forse dovrebbe essere (privato).


Solo per riferimento, non c'è magia nascosta accadendo con CanBuildFrom, quasi sempre va solo attraverso il newBuilder sopra:

  1. quando non si specifica il tipo di raccolta previsto, come in Seq(1,2).map(_+1) , l'unico oggetto disponibile è CanBuildFromcomes from l'oggetto associato a Seq ed è di tipo CanBuildFrom[Seq[_], T, Seq[T]]. Ciò significa che anche il risultato sarà uno Seq.

  2. Come la maggior parte degli oggetti da compagnia delle collezioni, il CanBuildFrom esempio Seq fornisce solo fa una cosa: chiamare Seq.newBuilder (che è definito in GenTraversableFactory ...)

Ecco perché CanBuildFrom per Vector utilizza un VectorBuilder.Ad esempio, in questo:

scala> Vector(1,2,3).map(_+1) 
res12: scala.collection.immutable.Vector[Int] = Vector(2, 3, 4) 

Il costruttore che è stato utilizzato è:

scala> implicitly[CanBuildFrom[Vector[Int], Int, Vector[Int]]].apply() 
res13: scala.collection.mutable.Builder[Int,Vector[Int]] = 
    [email protected] 
+0

OK, c'è un metodo 'newBuilder', e c'è una differenza tra' Builder' e 'Buffer. Poiché c'è un'altra bella risposta, la lascerò aperta per un po 'di tempo; al momento non posso davvero dire quale sia il migliore, grazie per la tua visione. Ma hai sollevato un'altra domanda: perché 'Seq.newBuilder' non restituisce un' VectorBuilder'? Non restituisce nemmeno un 'Builder', ed è persino una collezione più sofisticata? Ma sembra un'altra domanda, quindi se sei d'accordo, preferirei postarne un altro. – Beryllium

+0

Per me, sembra che tu stia suggerendo che le persone usano Seq.newBuilder, ma qualcuno lo fa? Se avessi avuto bisogno di costruire una mappa un po 'alla volta, penso che avrei usato un mutabile.Mappa e poi .toMappa, non MapBuilder. Raramente, userò CanBuildFrom in un caso speciale. Ma forse è questo il tuo punto, stai prendendo il punto di vista di qualcuno che si aggancia alle collezioni. –

+0

Qualcuno stava chiedendo dei pattern MVx, e ho guardato il mio primo codice di scala e ho trovato la mia confusione di principianti sul costruttore: https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/ principale/Scala/hom/LightBox.scala # L356 Spero che tu lo trovi divertente come me. –

1

Non c'è Vector mutevole. Per analogia a ListSetBuilder, il costruttore rimane vicino a ciò che sta costruendo.

mutable.StringBuilder è anomalo perché è un tipo utilizzato di frequente che è più di prima classe e tende a passare attraverso l'API. (Riceve una citazione nella panoramica delle collezioni e non richiede un'importazione. In effetti, ha un ruolo in this puzzler perché è leggermente diverso da Java StringBuilder ma potresti dimenticarti che lo stai usando.)

VectorBuilder è un'API pubblica. Lo newBuilder sugli oggetti associati ha più a che fare con il framework factory di raccolta e con CanBuildFrom. Nessuno dei due è citato in the overview dove spiega come fare le cose. Non ricordo eventuali frammenti che suggeriscono:

(ListBuffer.newBuilder[String] += "hello" += "world").result.toList 

Come si crea un Vector dipende da quello che stai facendo, ma la panoramica suggerisce i metodi di fabbrica sul compagno. Se hai già una collezione (magari non rigorosa), quindi toVector. Come fai a raccogliere qualsiasi cosa?

This is a good Q&A sulla scelta di Vettore su Elenco per il proprio Seq.

Come un dettaglio di implementazione, che VectorPointer cosa che si vede nel scaladoc include un grande commento:

// USED BY BUILDER 

Dal VectorPointer è private[immutable], costruttore deve rimanere lì come una questione pratica. Ciò suggerisce anche qualche pensiero su cosa esporre come API.

Inoltre, Vector reca un commento simile:

// in principle, most members should be private. however, access privileges must 
// be carefully chosen to not prevent method inlining 

Questi commenti indicano che i livelli di accesso non sono a casaccio.

Questa domanda è un'opportunità interessante per pensare al design del pacchetto. Può darsi che le collezioni di Scala siano un test di una macchia d'inchiostro di Rorschach, che rivela grande bellezza e simmetria, mentre, allo stesso tempo, per la mente disturbata, un grande squilibrio nell'universo. (Tipo di scherzare lì.)

+0

Quindi i punti principali sono: 'Builder' è vicino al suo edificio, si dovrebbe usare' Vector.newBuilder', e i privilegi di accesso possono essere scelti in modo tale che non impediscano l'inlining. Poiché c'è un'altra bella risposta, la lascerò aperta per un po 'di tempo; al momento non posso davvero dire quale sia il migliore, grazie per la tua visione. – Beryllium

+0

No, ho sepolto il mio punto principale nel mezzo: di solito non usi un costruttore (vedi il link alla panoramica). Se ne hai bisogno (in una funzione sensibile alle prestazioni), non importa molto come lo ottieni: implicito CanBuildFrom, esplicito da new o newBuilder. Una domanda interessante, si scopre. –

Problemi correlati