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