跳转到内容

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

50% developed
来自 Wikibooks,开放世界中的开放书籍

第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)[] 完全相同,即不可变字符元素的动态数组。类似地,wstring 等同于 immutable(wchar)[],而 dstring 等同于 immutable(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
华夏公益教科书