Ответ 1
Ассоциативные массивы требуют, чтобы их ключи были неизменными. Это имеет смысл, когда вы думаете о том, что, если он не является неизменным, тогда он может измениться, а это означает, что его хеш изменяется, а это означает, что когда вы снова получите значение, компьютер не найдет его. И если вы замените его, вы получите другое значение, добавленное в ассоциативный массив (так что у вас будет один с правильным хешем и один с неправильным хэшем). Однако, если ключ неизменен, он не может измениться, и поэтому такой проблемы нет.
До dmd 2.051 этот пример работал (который был bug). Теперь он исправлен, поэтому пример в TDPL больше не правильный. Однако это не так, что правила для ассоциативных массивов изменились, поскольку в них была ошибка, которая не была поймана. Пример составлен, когда он не должен был, и Андрей пропустил его. Он указан в официальных ошибках для TDPL и должен быть исправлен в будущих печатных изданиях.
Исправленный код должен использовать либо dictionary[word.idup]
, либо dictionary[to!string(word)]
. word.idup
создает дубликат word
, который является неизменным. to!string(word)
, с другой стороны, преобразует word
в string
наиболее подходящим образом. Поскольку word
является char[]
в этом случае, это будет использовать idup
. Однако, если word
уже был string
, тогда он просто вернул бы значение, которое было передано и не обязательно скопировано. Итак, в общем случае to!string(word)
- лучший выбор (особенно в шаблонных функциях), но в этом случае либо работает просто отлично (to!()
находится в std.conv
).
Технически возможно использовать a char[]
для string
, но, как правило, это плохая идея. Если вы знаете, что char[]
никогда не изменится, вы можете с ним справиться, но в общем случае вы рискуете проблемами, поскольку компилятор тогда предположит, что результат string
никогда не изменится, и это может генерировать неверный код. Это может быть даже segfault. Таким образом, не делайте этого, если профилирование не показывает, что вам действительно нужна дополнительная эффективность, чтобы избежать копирования, вы не можете иначе избежать копирования, сделав что-то вроде просто используя string
в первую очередь (так что никакое преобразование не было бы необходимо), и вы знаете, что string
никогда не будет изменен.
В общем, я бы не стал слишком беспокоиться об эффективности копирования строк. Как правило, вы должны использовать string
вместо char[]
, чтобы вы могли скопировать их (то есть скопировать их ссылку вокруг (например, str1 = str2;
), а не копировать все их содержимое, например dup
и idup
do) не беспокоясь о том, что это особенно неэффективно. Проблема с примером заключается в том, что stdin.byLine()
возвращает char[]
, а не string
(предположительно, чтобы избежать копирования данных, если это не необходимо). Итак, splitter()
возвращает a char[]
, поэтому word
является char[]
вместо string
. Теперь вместо idup
введите ключ splitter(strip(line.idup))
или splitter(strip(line).idup)
. Таким образом, splitter()
вернет string
, а не char[]
, но, вероятно, по существу так же эффективен, как idup
ing word
. Независимо от того, откуда исходный текст начинается, вместо string
следует char[]
, который заставляет вас idup
его где-то вдоль строки, если вы намереваетесь использовать его как ключ в ассоциативном массиве. В общем случае, однако, лучше просто использовать string
, а не char[]
. Тогда вам не нужно idup
что-либо.
EDIT:
На самом деле, даже если вы обнаружите ситуацию, когда кастинг от char[]
до string
кажется безопасным и необходимым, рассмотрите возможность использования std.exception.assumeUnique()
(документации). Это, по сути, предпочтительный способ преобразования изменчивого массива в неизменяемый, когда вам нужно и знать, что вы можете. Обычно это делается в тех случаях, когда вы создали массив, который вы не могли бы сделать неизменным, потому что вам приходилось делать это кусочками, но у которого нет других ссылок, и вы не хотите создавать его глубокую копию. Это не было бы полезно в таких ситуациях, как пример, о котором вы спрашиваете, поскольку вам действительно нужно скопировать массив.