Gli array associativi richiedono che le loro chiavi siano immutabili. Ha senso quando si pensa al fatto che se non è immutabile, allora potrebbe cambiare, il che significa che il suo hash cambia, il che significa che quando si va a recuperare il valore, il computer non lo troverà. E se vai a sostituirlo, finirai con un altro valore aggiunto all'array associativo (quindi, ne avrai uno con l'hash corretto e uno con un hash errato). Tuttavia, se la chiave è immutabile, non può cambiare e quindi non esiste un problema di questo tipo.
Prima di dmd 2.051, l'esempio funzionava (che era un bug). Ora è stato risolto, quindi l'esempio in TDPL non è più corretto. Tuttavia, non è tanto il caso che le regole per gli array associativi siano cambiate in quanto vi è stato un bug in esse che non è stato catturato. L'esempio è compilato quando non dovrebbe avere, e Andrei lo ha perso. È elencato nel official errata for TDPL e dovrebbe essere corretto nelle stampe future.
Il codice corretto deve utilizzare dictionary[word.idup]
o dictionary[to!string(word)]
. word.idup
crea un duplicato di word
che è immutabile. to!string(word)
, d'altra parte converte word
in un string
nel modo più appropriato.Come word
è un char[]
in questo caso, che sarebbe quello di utilizzare idup
. Tuttavia, se word
fosse già un string
, restituirebbe semplicemente il valore passato e non copiarlo inutilmente. Quindi, nel caso generale, to!string(word)
è la scelta migliore (in particolare nelle funzioni basate su modelli), ma in questo caso, funziona perfettamente (to!()
è in std.conv
).
È tecnicamente possibile trasmettere un char[]
a string
, ma in genere è una cattiva idea. Se tu rispondi allo che il char[]
non cambierà mai, allora puoi farla franca, ma nel caso generale, stai rischiando problemi, dal momento che il compilatore supporterà che lo string
risultante non possa mai cambiare, e potrebbe generare codice che non è corretto. Potrebbe persino segfault. Quindi, non farlo a meno che la profilatura dimostri che hai davvero bisogno dell'efficienza extra di evitare la copia, altrimenti non puoi evitare la copia facendo qualcosa come semplicemente usando uno string
in primo luogo (quindi non sarebbe necessaria alcuna conversione) e tu sai che il string
non sarà mai cambiato.
In generale, non mi preoccuperei troppo dell'efficienza della copia delle stringhe. In genere, dovresti utilizzare anziché char[]
, quindi puoi copiarli (ovvero copiare il loro riferimento in giro (ad esempio str1 = str2;
) anziché copiare l'intero contenuto come dup
e idup
do) senza preoccuparti che sia particolarmente inefficiente. Il problema con l'esempio è che stdin.byLine()
restituisce uno char[]
anziché uno string
(presumibilmente per evitare di copiare i dati se non è necessario). Quindi, splitter()
restituisce un char[]
e così word
è un char[]
anziché uno string
. Ora, è possibile eseguire splitter(strip(line.idup))
o splitter(strip(line).idup)
anziché idup
. In questo modo, splitter()
restituirebbe uno string
anziché char[]
, ma probabilmente è altrettanto efficiente quanto idup
in word
. A prescindere, a causa di dove il testo proviene originariamente, è uno char[]
invece di uno string
, che obbliga a idup
da qualche parte lungo la linea se si intende utilizzarlo come chiave in un array associativo. Nel caso generale, tuttavia, è meglio usare solo string
e non char[]
. Quindi non è necessario per nulla idup
.
EDIT:
In realtà, anche se si trova una situazione in cui la fusione char[]
-string
sembra sia sicuro e necessario, considerare l'utilizzo di std.exception.assumeUnique()
(documentation). È essenzialmente il modo preferito di convertire un array mutabile in uno immutabile quando è necessario e sapere che è possibile. Normalmente si farebbe nei casi in cui hai costruito un array che non potresti rendere immutabile perché dovevi farlo a pezzi ma che non ha altri riferimenti e non vuoi crearne una copia profonda. Non sarebbe utile in situazioni come l'esempio che stai chiedendo, dato che hai davvero bisogno di copiare l'array.
FYI per chiunque venga a questa domanda mesi o anni dopo: ci sono altre cose che non funzionano nell'esempio stampato. Usa ulong non uint per il tipo di array associativo e devi importare std.array per ottenere lo splitter. Vedi http://www.digitalmars.com/d/archives/digitalmars/D/learn/problems_with_DPL_example._30009.html – DarenW