Vis*_*hao 16 string associative-array d
我是D编程语言的新手,刚开始阅读D编程语言书.
尝试一个关联数组示例代码时遇到错误
#!/usr/bin/rdmd
import std.stdio, std.string;
void main() {
uint[string] dict;
foreach (line; stdin.byLine()) {
foreach (word; splitter(strip(line))) {
if (word in dict) continue;
auto newId = dict.length;
dict[word] = newId;
writeln(newId, '\t', word);
}
}
}
Run Code Online (Sandbox Code Playgroud)
DMD显示此错误消息:
./vocab.d(11):错误:关联数组只能用不可变键赋值,而不是char []
我正在使用DMD编译2.051
我猜测关联数组的规则自TDPL书以来已经发生了变化.
我应该如何使用带有字符串键的关联数组?
谢谢.
更新:
我在本书的后半部分找到了解决方案.
在放入数组之前使用string.idup创建重复的不可变值.
所以
dict[word.idup] = newId;
Run Code Online (Sandbox Code Playgroud)
会做的.
但这有效吗?
Jon*_*vis 25
关联数组要求它们的键是不可变的.当你想到如果它不是不可变的那个事实时它就有意义了,那么它可能会改变,这意味着它的哈希值会发生变化,这意味着当你再次获取值时,计算机将无法找到它.如果你去替换它,你将最终添加到关联数组的另一个值(所以,你将有一个具有正确的哈希值和一个具有不正确的哈希值).但是,如果密钥是不可变的,则它不能改变,因此不存在这样的问题.
在dmd 2.051之前,该示例有效(这是一个错误).它现在已被修复,因此TDPL中的示例不再正确.然而,关联数组的规则已经发生了变化,因为它们中存在一个未被捕获的错误.这个例子在不应该编译时编译,而Andrei错过了它.它已在TDPL的官方勘误表中列出,并应在未来的印刷中修复.
更正的代码应使用dictionary[word.idup]或dictionary[to!string(word)].word.idup创建一个word不可变的副本.to!string(word)另一方面,以最恰当的方式转换word为a string.由于word是char[]在这种情况下,这将是使用idup.但是,如果word已经是a string,那么它只会返回传入的值而不是不必要地复制它.因此,在一般情况下,to!string(word)是更好的选择(特别是在模板化函数中),但在这种情况下,要么工作得很好(to!()进入std.conv).
在技术上可以将a转换char[]为a string,但这通常是一个坏主意.如果您知道的是,char[]永远不会改变,那么你就可以过关了,但在一般情况下,你冒着问题,因为编译器会再假设产生的string无法改变,而且它可以生成代码,这是不正确.它甚至可能是段错误.所以,不要这样做,除非分析表明你确实需要避免副本的额外效率,否则你不能通过做一些事情来避免副本string(例如,不需要转换),你知道的string永远不会改变.
一般来说,我不会太担心复制字符串的效率.一般来说,你应该使用string而不是char[],所以你可以复制它们(这是复制它们的参考(例如str1 = str2;)而不是复制它们的全部内容dup,idup而不必担心它特别低效).该示例的问题是stdin.byLine()返回a char[]而不是a string(可能是为了避免在不必要时复制数据).所以,splitter()返回一个char[],所以word是一个char[]而不是一个string.现在,你可以做splitter(strip(line.idup))或splitter(strip(line).idup)代替idup键.那样,splitter()会返回一个string而不是char[],但这可能基本上和iduping 一样有效word.无论如何,因为文本来自最初的位置,所以它是a char[]而不是a string,idup如果您打算将它用作关联数组中的键,则会强制您沿着该行的某个位置移动它.然而,在一般情况下,最好只使用string而不是char[].那你就不需要idup任何东西了.
编辑:
其实,即使你找到的情况下,从铸造char[]到string似乎既安全又必要,可以考虑使用std.exception.assumeUnique()(文档).当你需要并知道可以的时候,它本质上是将可变数组转换为不可变数组的首选方法.它通常会在你构造了一个你不能创建的数组的情况下完成,因为你必须分成几部分但没有其他引用,并且你不想创建它的深层副本.但是在你要问的例子中它没有用,因为你确实需要复制数组.
| 归档时间: |
|
| 查看次数: |
2100 次 |
| 最近记录: |