Rust-Collections und Strings
Sammlungen sind die häufigste Form der Datenspeicherung in Datenstrukturen. Die Rust-Standardbibliothek bietet eine reichhaltige Auswahl an Sammlungstypen, die Entwicklern helfen, Datenstrukturoperationen zu handhaben.
Vektor
Ein Vektor ist eine einzelne Datenstruktur, die mehrere Werte speichert, und er speichert Werte desselben Typs linear im Speicher.
Ein Vektor ist eine lineare Liste, in Rust als Vec<T> dargestellt.
Vektoren werden ähnlich wie Listen verwendet. Wir können einen Vektor eines angegebenen Typs auf diese Weise erstellen:
let vector: Vec<i32> = Vec::new(); // 创建类型为 i32 的空向量 let vector = vec![1, 2, 4, 8]; // 通过数组创建向量
Bei der Verwendung linearer Listen müssen wir oft Anfügeoperationen durchführen. Das Anfügen ist jedoch im Wesentlichen dasselbe wie die push-Operation des Stacks, daher haben Vektoren nur die push-Methode, um ein einzelnes Element anzufügen:
, wird der Vektor einen Fehler zurückgeben.
let mut vector = vec![1, 2, 4, 8];
vector.push(16);
vector.push(32);
vector.push(64);
println!("{:?}", vector);
}
Ausgabe:
[1, 2, 4, 8, 16, 32, 64]
Die append-Methode wird verwendet, um einen Vektor an das Ende eines anderen anzuhängen:
Beispiel
let mut v1: Vec<i32> = vec![1, 2, 4, 8];
let mut v2: Vec<i32> = vec![16, 32, 64];
v1.append(&mut v2);
println!("{:?}", v1);
}
Ausgabe:
[1, 2, 4, 8, 16, 32, 64]
Die get-Methode wird verwendet, um einen Wert aus einem Vektor abzurufen:
Beispiel
let mut v = vec![1, 2, 4, 8];
println!("{}", match v.get(0) {
Some(value) => value.to_string(),
None => "None".to_string()
});
}
Ausgabe:
1
Da die Länge eines Vektors nicht logisch abgeleitet werden kann, kann die get-Methode nicht garantieren, dass ein Wert zurückgegeben wird, daher ist der Rückgabetyp der get-Methode das Option-Enum, das None sein kann.
Dies ist eine sichere Möglichkeit, einen Wert zu erhalten, aber es ist etwas umständlich zu schreiben. Wenn garantiert werden kann, dass der Index innerhalb des gültigen Bereichs des Vektors liegt, kann auch die Array-Indizierungssyntax verwendet werden:
Beispiel
let v = vec![1, 2, 4, 8];
println!("{}", v[1]);
}
Ausgabe:
2
Aber wenn wir versuchen, auf v zuzugreifen
Über einen Vektor iterieren:
Beispiel
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
}
Ausgabe:
100 32 57
Wenn Sie den Wert einer Variable während der Iteration ändern müssen:
Beispiel
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
}
String
Der Typ String wurde bis zu diesem Kapitel ausgiebig verwendet, daher sind viele seiner Methoden den Lesern bereits vertraut. Dieses Kapitel stellt hauptsächlich String-Methoden und UTF-8-Eigenschaften vor.
Erstellen eines neuen Strings:
let string = String::new();
Konvertieren von Basistypen in Strings:
let one = 1.to_string(); // 整数到字符串 let float = 1.3.to_string(); // 浮点数到字符串 let slice = "slice".to_string(); // 字符串切片到字符串
Strings, die UTF-8-Zeichen enthalten:
let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("你好");
let hello = String::from("Olá");
let hello = String::from("Здравствуйте");
let hello = String::from("Hola");
Anhängen an einen String:
let mut s = String::from("run");
s.push_str("oob"); // 追加字符串切片
s.push('!'); // 追加字符
Strings mit dem +-Zeichen verketten:
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;
Diese Syntax kann auch String-Slices enthalten:
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = s1 + "-" + &s2 + "-" + &s3;
Verwenden des format!-Makros:
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);
String-Länge:
let s = "hello"; let len = s.len();
Hier ist der Wert von len 5.
let s = "你好"; let len = s.len();
Hier ist der Wert von len 6. Da Chinesisch UTF-8-kodiert ist, ist jedes Zeichen 3 Bytes lang, daher ist die Länge 6. Rust unterstützt jedoch UTF-8-Zeichenobjekte. Wenn Sie die Anzahl der Zeichen zählen möchten, können Sie die Zeichenkette zunächst in eine Sammlung von Zeichen umwandeln:
let s = "hello你好"; let len = s.chars().count();
Hier ist der Wert von len 7, da insgesamt 7 Zeichen vorhanden sind. Das Zählen von Zeichen ist viel langsamer als das Ermitteln der Byte-Länge.
Iteration über eine Zeichenkette:
Beispiel
let s = String::from(hello Chinese);
for c in s.chars() {
println!("{}", c);
}
}
Ausgabe:
h e l l o 中 文
Abrufen eines einzelnen Zeichens aus einer Zeichenkette:
Beispiel
let s = String::from(EN Chinese);
let a = s.chars().nth(2);
println!("{:?}", a);
}
Ausgabe:
Some('中')
Hinweis: Die Funktion nth ist eine Methode, um einen Wert aus einem Iterator abzurufen. Bitte verwenden Sie sie nicht auf diese Weise während der Iteration! Denn die Länge jedes Zeichens in UTF-8 ist nicht unbedingt gleich!
Wenn Sie eine Teilzeichenkette aus einer Zeichenkette extrahieren möchten:Beispiel
let s = String::from(EN Chinese);
let sub = &s[0..2];
println!("{}", sub);
}
Ausgabe:
EN
Beachte jedoch, dass diese Verwendung ein UTF-8-Zeichen aufteilen kann! Dies wird einen Fehler verursachen:
Beispiel
let s = String::from(EN Chinese);
let sub = &s[0..3];
println!("{}", sub);
}
Ausgabe:
thread 'main' panicked at 'byte index 3 is not a char boundary; it is inside '中' (bytes 2..5) of `EN中文`', src\libcore\str\mod.rs:2069:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
Map
Maps sind in anderen Sprachen weit verbreitet. Die am häufigsten verwendete ist die Schlüssel-Wert-Hashmap.
Erstellen einer neuen Hashmap:
Beispiel
fn main() {
let mut map = HashMap::new();
map.insert("color", "red");
map.insert("size", "10 m^2");
println!("{}", map.get("color").unwrap());
}
Hinweis: Der Grund, warum wir den generischen Typ der Hashmap nicht deklariert haben, ist der automatische Typinferenzmechanismus von Rust.
Ausgabe:
red
Die insert- und get-Methoden sind die beiden am häufigsten verwendeten Methoden einer Map.
Maps unterstützen Iteratoren:
Beispiel
fn main() {
let mut map = HashMap::new();
map.insert("color", "red");
map.insert("size", "10 m^2");
for p in map.iter() {
println!("{:?}", p);
}
}
Ausgabe:
("color", "red")
("size", "10 m^2")
Die iterierten Elemente sind Tupel, die Schlüssel-Wert-Paare darstellen.
Rusts map ist eine sehr praktische Datenstruktur. Wenn man die insert-Methode verwendet, um ein neues Schlüssel-Wert-Paar hinzuzufügen, und derselbe Schlüssel bereits existiert, wird der entsprechende Wert direkt überschrieben. Wenn man „sicher einfügen“ möchte, das heißt, die Einfügung erst ausführen, nachdem bestätigt wurde, dass ein Schlüssel derzeit nicht existiert, kann man Folgendes tun:
map.entry("color").or_insert("red");Das bedeutet: Wenn es kein Schlüssel-Wert-Paar mit dem Schlüssel "color" gibt, füge es hinzu und setze den Wert auf "red"; andernfalls wird es übersprungen.
Wenn bestätigt wurde, dass ein Schlüssel existiert, und man den zugehörigen Wert direkt ändern möchte, gibt es einen schnelleren Weg:
Beispiel
fn main() {
let mut map = HashMap::new();
map.insert(1, "a");
if let Some(x) = map.get_mut(&1) {
*x = "b";
}
}