跳转到内容

D(编程语言)/d2/字符串和动态数组

50% developed
来自维基教科书,开放的书籍,开放的世界

第 8 课:字符串和动态数组

[编辑 | 编辑源代码]

在本节中,您将深入了解字符串。同时,您也将学习另一种类型:动态数组。

入门代码

[编辑 | 编辑源代码]

动态数组

[编辑 | 编辑源代码]
import std.stdio;

void main()
{
    int[] a = [1,2,3,4];
    int[] b = [5,6];
    auto c = a ~ b;
    writeln(c); // [1,2,3,4,5,6]
    
    writeln(c.length);  // 6
    
    int* ptr_c = c.ptr;
    ptr_c[0] = 3;
    writeln(c); // [3,2,3,4,5,6]
}

不可变类型和字符串

[编辑 | 编辑源代码]
import std.stdio;

void main()
{
    // Concept:  Immutable
    immutable(int) a = 10;
    // a = 11;  Error:  cannot modify immutable
    immutable a = 10;
    
    // Concept:  Strings as Arrays
    immutable(char)[] str = "Hello";
    auto str1 = str ~ "1";
    writeln(str1); // Hello1
    writeln(str1.length);  // 6  
    // str1[] = 'z'; error! str1's elements are not mutable
    char[] mutablestr1 = str1.dup;
    
    // Concept: Char Literals
    mutablestr1[] = 'z';  // 'z' is not a string, but a char
    
    str1 = mutablestr1.idup;  // The str1 itself is mutable
    // only its elements are not mutable
    writeln(str1);  // zzzzzz
}

动态数组

[编辑 | 编辑源代码]

动态数组与静态数组

[编辑 | 编辑源代码]

在上一课中,您学习了静态数组。动态数组与静态数组不同,它们没有固定长度。本质上,动态数组是一个包含以下信息的结构

  1. 指向第一个元素的指针
  2. 整个数组的长度

您可以像这样创建一个动态数组

int[] a;

您可以创建一个以特定长度初始化的动态数组

int[] a = new int[](5);

您将在稍后学习有关 new 关键字的更多信息。
用单个值填充数组的语法对于静态数组和动态数组是相同的

int[] a = [1,2,3];
a[] = 3;
writeln(a); // [3, 3, 3]

动态数组的索引方式与静态数组相同。访问特定索引处的元素的语法也是相同的

a[2];

但是,由于动态数组的长度在编译时未知,因此编译器无法检查您访问的索引是否真的在该长度范围内。像这样的代码将编译,但也将导致运行时范围违规错误

int[] a = [1,2,3];
writeln(a[100]);  //Runtime error, Range violation

动态数组的操作

[编辑 | 编辑源代码]

可以使用 ~ 运算符将动态数组与其他动态数组甚至静态数组组合。将新元素附加到数组使用相同的运算符。

int[] a = [1,2];
auto b = a ~ [3,4];
writeln(b);  //[1, 2, 3, 4]
b ~= 5;  // same as b = b ~ 5;
writeln(b);  //[1, 2, 3, 4, 5]

除非您确定 my_dynamic_arr.length 等于 my_static_arr.length,否则您不应该将动态数组分配给静态数组(my_static_arr = my_dynamic_arr;)。否则,将发生运行时错误。但是,您始终可以将静态数组分配给动态数组变量,因为如果静态数组的长度太大,动态数组将自动调整大小。

int[] a = [9,9,9,9,9,9];
int[3] b = [1,2,3];
int[200] c;
a = b;
writeln(a);  // [1, 2, 3]
a = c;
writeln(a.length); // 200

int[] d = [5,4,3];
b = d;  // OK: lengths are both 3
// c = d;  runtime error! lengths don't match.

将动态数组传递给函数

[编辑 | 编辑源代码]

动态数组按值传递给函数。这意味着,当您将动态数组传递给函数时,包含指向第一个元素的指针和长度的结构将被复制并传递。

void tryToChangeLength(int[] arr)
{
    arr.length = 100;
}
void main()
{
    int[] a = [1,2];
    tryToChangeLength(a);
    writeln(a.length);  // still 2
}

您在上节课中了解到,您可以通过添加 ref 修饰符来使事物按引用传递而不是按值传递。

数组和其他属性

[编辑 | 编辑源代码]

这些属性适用于静态数组和动态数组

属性 描述
.init 对于静态数组,它返回一个数组,其中每个元素都初始化为其默认值。
.sizeof 返回数组在内存中的大小。
.length 返回数组中的元素数量。这在静态数组中是固定的。
.ptr 返回指向数组第一个元素的指针。
.dup 创建一个动态数组,它是数组的副本,并返回它。
.idup 类似于 .dup,但副本的元素是 immutable
.reverse 返回元素按反序排列的数组。
.sort 对数组中的元素进行就地排序并返回结果。

还有其他属性,这些属性是每个对象或表达式的共同属性。其中两个属性是 .init.sizeof 属性。

不可变类型

[编辑 | 编辑源代码]

在 D 中,immutable 是一个存储类,就像 auto 一样。它将类型转换为不可修改的类型。

immutable(int) fixed_value = 37;
immutable int another_value = 46;

请注意,immutable(type) 对编译器而言与 immutable type 相同。

存储类和 auto

[编辑 | 编辑源代码]

当您有一个像 immutable 这样的存储类时,您可以省略 auto 进行类型推断。

immutable fixed_value = 55;

编译器会推断不可变类型的具体类型。下面的代码示例无效,因为编译器无法推断类型。

immutable fixed_value;  //Error!

使用 immutable 变量

[编辑 | 编辑源代码]

这是一种允许且完全有效的代码。

immutable(int) a = 300;
int b = a;

它只是将 b 设置为 a 的值。b 不必是 immutable。如果你要取引用,情况就会改变。

immutable(int) a = 13;
immutable(int)* b = &a;
// int* c = &a;  Error.

你可以将 immutable 移除,但如果你使用此技巧修改不可变值,结果是未定义的。

immutable(int) a = 7;
int* b = cast(int*)&a;
// Just make sure you do not modify a
// through b, or else!

字符串作为数组

[编辑 | 编辑源代码]

从第一课开始你就接触过字符串。stringimmutable(char)[] 完全相同,即不可变字符元素的动态数组。类似地,wstringimmutable(wchar)[] 相同,dstringimmutable(dchar)[] 相同。

字符串属性

[编辑 | 编辑源代码]

字符串具有与动态数组相同的内置属性。一个有用的属性是 .dup 属性,用于创建字符串的 char[] 可变副本,如果你想修改字符串的单个字符。

string a = "phobos";
char[] b = a.dup;
b[1] = 'r';
b[4] = 'e';
writeln(b);  // probes

.idup 属性用于创建现有字符串的副本,或用于创建 char[] 的字符串副本。

string a = "phobos";
string copy_a = a.idup;
char[] mutable_a = copy_a.dup;
mutable_a[3] = 't';
copy_a = mutable_a.idup;
writeln(mutable_a); // photos
writeln(a); // phobos

字符字面量

[编辑 | 编辑源代码]

char 字面量用单引号括起来。还有 wchardchar 字面量。

auto a = "a"; // string
auto b = 'b'; // char
auto c = 'c'c; // char
auto d = 'd'w; // wchar
auto e = 'e'd; // dchar
华夏公益教科书