*Komplexe Datentypen
Vektoren
Diese könnte man als die erweiterte Version von Arrays bezeichnen. Ein bisschen analog zu &str und Strings. Vielleicht stellt sich jemand die Frage, warum man dann nicht gleich Vektoren verwendet, wenn die mehr können. Aus meinem Verständnis heraus, wird hier nur wieder die strenge Typisierung in Rust sichtbar. Je länger ich damit arbeite, desto mehr gefällt es mir auch. Sie zwingt den Programmierer genau über die Konzepte nachzudenken. Ein Array hat eine fixe Länge, dh. ich verwende es dort, wo ich weiß dass es fixe Größen gibt, ansonsten habe ich für veränderte Größen und fixen Datentypen eben einen Vektor zur Verfügung. Wie ist so ein Vektor aufgebaut? Es gibt auch hier verschiedene Herangehensweisen. Ein unbefleckter Vektor sieht so aus.
fn main(){
let vector1:Vec<i32> = Vec::new();
}
Diese Deklaration verlangt nach einer Typannotation. Das liegt daran, wenn der Vektor später gefüllt wird, es zu keinen Unstimmigkeiten kommt. Im Gegensatz dazu, wenn der Vektor gleich zu Beginn Werte erhält, ist so etwas nicht nötig.
let vector2 = vec![15,10,14,13,11];
Man beachte das Rufzeichen, vor der Werteeingabe. Also, ein Macro. Hier kann man aber auch den Datentyp im Vorfeld angeben.
let vector3:Vec<u8> = vec![15,10,14,13,11];
Ausgabe
Ich habe es mit ein paar versucht. Es ist dem Compiler egal, solange es ein Integer ist. Allerdings erschließt sich mir nicht der Nutzen, warum ich die Angabe in der selben Zeile machen sollte; höchstens wenn bestimmte Grenzen nicht überschritten werden sollten und ich das vergessen könnte. (der u8 geht nur bis 255) Jetzt befüllen wir mal den leeren Vektor. Man kann hier einfach .push(Wert) verwenden.
vector1.push(1);
nicht vergessen, dass vector1 noch als let mut vector1 umbenannt wird. Man muss hier aber zugeben, dass diese Methode evtl. etwas langwierig wirkt. Was ist, wenn man diesem Datentypen nicht nur vereinzelt, sondern gleich mal größere Blöcke an Daten zuweisen möchte? Da wird man vermutlich alt. vector1.push(2) .... vector1.push(17) ... ich kann nicht mehr. Nein, man kann so einen Anhang zB über ein Array zuweisen. In diesem Fall mit .extend(array)
let array1=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
vector1.extend(array1);
Ausgabe
Oder für uns ganz Faule (oder sagen wir besser Erfindungsreichen), füllen wir den Vektor einfach mit einer For-Schleife.
for x in 21..100{
vector1.push(x);
}
Ausgabe
Das ist doch nett, was?
Nicht vergessen, der erste 1er war vom vorherigen .push(1) schon da. Um ehrlich zu sein, nervt mich der überflüssige 1er; den löschen wir.
vector1.remove(0);
Die 0 war im übrigen Index 0, die erste Einheit im Vektor1. Wisst ihr was, der Vektor ist mir eh viel zu lang, den stutzen wir mal gehörig und zwar mit der Anweisung .drain(Range)
vector1.drain(16..=77);
Ausgabe
Die Methode war mir selbst noch vollkommen fremd. Es geht auch, dass die gelöschte Passage in einen neuen (Mistkübel)-Vektor gespeichert wird. Das mache ich aber ein anderes Mal, das bringt uns zu weit vom Thema weg.
Früher oder später wollen wir vielleicht was suchen im Vektor, oder wissen was in einem bestimmten Index steht. Das hat einen bestimmten Aufbau. Es gibt 2 Varianten, eine davon gilt als unsicher, weil diese auch außerhalb des Indexes zugreifen könnten (Das verursacht einen Programmabsturz, oder im Vorfeld einen Compilerfehler). Die andere ist sicher, aber etwas komplexer. Fangen wir mit der einfachen Methode an. Diese besagt eigentlich nur, welcher Wert bei welchem Index steht. (Die andere Methode eigentlich auch, im Anschluss mache ich noch eine Suchfunktion)
let siebzehn = vector1[17];
Ausgabe
Versuchen wir mal eines deutlich außerhalb des Indexbereiches.
let neunzig = vector1[90];
Ausgabe
Der Begriff panicked bedeutet sinngemäß "abgestürzt". In diesem Fall hat der Compiler den Fehler aufgehalten. Rust sorgt dafür, dass nicht in den freien Speicher geschrieben wird. Das ist in etwa so, wie wenn man einen Hammer hat und blind eine Leiste langnagelt, bis man ins Leere haut. Sagen wir mal, die Methode hat etwas unbeholfenes und leicht brachiales. Welche Vorgehensweise ist nun eleganter (wenn auch aufwendiger)? Mit einer Mischung aus match, .get, Some, und None besteht ein sauberer Weg. Das Ziel ist es, dass der Wert ausgegeben wird, wenn er vorhanden ist und wenn nicht, eine Fehlermeldung erzeugt wird, sowie das Programm intakt bleibt.
match vector1.get(10){
Some(value)=>println!("Der Wert auf Index 10 = {}", value),
None => println!("Diesen Index gibt es nicht"),
}
Ausgabe
Wir prüfen also mit match ob es Index 10 gibt. Falls ja, wird Some (die Prüfinstanz) in die Variable value gespeichert und mit println! ausgegeben. Falls nicht, fällt die Prüfung auf None und gibt eine Fehlermeldung aus. So und zum Vergleich ein Beispiel, wo None für den Wert zuständig ist.
match vector1.get(90){
Some(value)=>println!("Der Wert auf Index 10 = {}", value),
None => println!("Diesen Index gibt es nicht"),
}
Ausgabe
So und jetzt, wie versprochen, noch eine richtige Sucheinheit. Ich bau die mit einer for-Schleife auf. Bestimmt gibt es noch andere, das ist die, welche ich kann und dafür geeignet ... sein sollte. Ja, witzig, was man manchmal zufällig draufkommt, wenn man denkt, das wüsste man schon. Ich kenne offenbar noch keine gute Methode für das durchsuchen von Datenstrukturen. Das wird wohl demnächst ein Thema werden. Mit der For-Schleife gehts zwar auch, aber es ist nicht gerade optimal. Ich kann eine Ausgabe und eine Fehlermeldung implementieren, allerdings hat das zur Folge, dass die For-Schleife (wofür sie geschaffen ist) durchgehend pro Index sagt, dass der Wert dort nicht gefunden wurde. Und das eine Mal, wo er vorhanden ist, da ist er eben vorhanden. Entsprechend habe ich jetzt Code gebastelt, wo halt nur vorhanden ist, falls es da ist und wenn nicht, gibts nix. Sehr unzufriedenstellend.
let search = 7;
for x in vector1{
if x == search{
println!("{} ist in vector1 enthalten", search);
}
}
Ich gelobe Besserung.
Zum Schluss nochmal die Zusammenfassung in gewohnter Manier.
fn main(){
let mut vector1:Vec<i32> = Vec::new();
let vector2 = vec![15,10,14,13,11];
let vector3:Vec<u8> = vec![15,10,14,13,11];
println!("Vector3 = {:?}", vector3);
vector1.push(1);
let array1=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
vector1.extend(array1);
for x in 21..100{
vector1.push(x);
}
println!("Vector1_for_labeled = {:?}", vector1);
vector1.remove(0);
println!("Vector1 = {:?}", vector1);
vector1.drain(16..=77);
println!("Vector1_drained = {:?}", vector1);
let siebzehn = vector1[17];
println!("{}",siebzehn);
// let neunzig = vector1[90];
// println!("{}",neunzig);
match vector1.get(10){
Some(value)=>println!("Der Wert auf Index 10 = {}", value),
None => println!("Diesen Index gibt es nicht"),
}
match vector1.get(90){
Some(value)=>println!("Der Wert auf Index 10 = {}", value),
None => println!("Diesen Index gibt es nicht"),
}
let search = 7;
for x in vector1{
if x == search{
println!("{} ist in vector1 enthalten", search);
}
}
}
Ausgabe
und Grüße vom Editor