D(程式語言)/d2/字串和動態陣列
在本節中,您將深入瞭解字串。同時,您也將學習另一種型別:動態陣列。
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
}
在上一課中,您學習了靜態陣列。動態陣列與靜態陣列不同,它們沒有固定長度。本質上,動態陣列是一個包含以下資訊的結構
- 指向第一個元素的指標
- 整個陣列的長度
您可以像這樣建立一個動態陣列
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 相同。
當您有一個像 immutable 這樣的儲存類時,您可以省略 auto 進行型別推斷。
immutable fixed_value = 55;
編譯器會推斷不可變型別的具體型別。下面的程式碼示例無效,因為編譯器無法推斷型別。
immutable fixed_value; //Error!
這是一種允許且完全有效的程式碼。
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!
從第一課開始你就接觸過字串。string 與 immutable(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 字面量用單引號括起來。還有 wchar 和 dchar 字面量。
auto a = "a"; // string
auto b = 'b'; // char
auto c = 'c'c; // char
auto d = 'd'w; // wchar
auto e = 'e'd; // dchar