我尝试编译以下代码:
import std.algorithm;
void main()
{
string[] x = ["ab", "cd", "ef"]; // 'string' is same as 'immutable(char)[]'
string space = " ";
char z = joiner( x, space ).front(); // error
}
使用dmd
的编译以错误结束:
test.d(8): Error: cannot implicitly convert expression (joiner(x,space).front()) of type dchar to char
将char z
更改为dchar z
确实修复了错误消息,但我很感兴趣的是它最初出现的原因。
为什么joiner(string[],string).front()
的结果是dchar而不是char?
(文档中没有这方面的内容http://dlang.org/phobos/std_algorithm.html#joiner)
所有字符串都被视为dchar
的范围。这是因为dchar
保证是单个码点,因为在UTF-32中,每个代码单元都是一个码点,而在UTF-8(char
)和UTF-16(wchar
)中,每个码点的代码单元数量不同。所以,如果你在单个char
或wchar
上操作,你会在多个字符上操作,而不是整个字符,这将是非常糟糕的。如果你对unicode了解不多,我建议你阅读Joel Spolsky的这篇文章。它很好地解释了事情。
在任何情况下,因为对单个char
s和wchar
s进行操作都没有意义,所以char
和wchar
的字符串被视为dchar
的范围(ElementType!string
是dchar
),这意味着就范围而言,它们没有length
(hasLength!string
是false
-需要使用walkLength
来获得它们的长度),不可切片(hasSlicing!string
是false
),并且是不可索引的(isRandomAccess!string
是false
)。这也意味着,任何从任何类型的字符串构建新范围的东西都将导致dchar
的范围。CCD_ 27就是其中之一。有些函数为了提高效率,可以理解unicode和特殊情况字符串,尽可能利用长度、切片和索引,但除非它们的结果最终是原始字符串的切片,否则它们返回的任何范围都必须由dchar
s组成。
因此,任何字符范围上的front
都将始终是dchar
,而popFront
将始终弹出一个完整的代码点。
如果你对音域了解不多,我建议你读这篇文章。这是一本关于D的书中的一章,这本书是在线的,也是目前我们最好的范围教程。我们真的应该在dlang.org上找到一篇关于范围(包括它们如何处理字符串)的合适文章,但还没有人抽出时间来写。无论如何,您至少需要对范围有一个基本的了解,才能使用大量D的标准库(尤其是std.algorithm),因为它使用得非常多。