Reflexionen über die Programmiersprache Rust 18

(edited)

*Ownership

Ich glaub, das habe ich schon mal angekündigt. Das Thema ist ziemlich zentral und trotzdem konnten wir uns nicht schon viel früher darum kümmern, weil einfach ein gewisses Wissen dafür notwendig ist, um die Zusammenhänge deutlicher verstehen zu können.

Bevor wir in die Tiefe gehen, zuerst mal der Nutzen von Ownership in Rust.
Es gibt eine Grundregel in Rust, die besagt, dass 1 Variable, 1 Wert besitzen kann und darf. Und wenn die Variable oder der Wert herumgeschippert wird, dann streng typisiert. Zum Thema Ownership gibt es einige Bereiche.

*Shadowing
*Scope
*Referenzen/Borrowing
*Clone/Copy

und im Allgemeinen die "Lebensdauer" eines Wertes.

Shadowing
oder in Deutsch wird es als "verschatten" übersetzt. Es wird quasi zum Überschreiben von Variablen verwendet, die wiederverwendbar sind. ZB. kann man eine Nutzereingabe, wenn man nichts Spezielles damit vorhat, immer wieder in der Variable input speichern. Um zu verstehen, was passiert, hier ein Beispiel. (machen wirs aber ohne Benutzer, sonst muss ich so viel schreiben^^)

fn main(){
    let x = 1;
    println!("x1={}",x);
    let x = 2; // Das erste x wird "überschattet" und bekommt einen neuen Wert.
    println!("x2={}",x);
}

Ausgabe
image.png

Wenn mans genau nimmt, unspektakulär. Aber es ist trotzdem gut zu wissen, denn ich hätte und hatte aus meiner Unwissenheit heraus, einfach immer weitere, unnötige Variablen deklariert.

Scope
oder im Deutschen als Geltungsbereich bezeichnet, wird verwendet um eine Variable, nach bestimmten Regeln, nur in einem bestimmten Rahmen gültig zu sein.

let x = 1;
    println!("x oberhalb der Klammern={}",x);
    {
        println!("x in der Klammern, BEVOR x in den Klammern definiert wurde={}",x);
        let x = 2;
        println!("x in der Klammern, NACHDEM x in den Klammern definiert wurde={}",x);

    }
    println!("x unterhalb der Klammer={}",x);

Ausgabe

image.png

Zugegeben, das hat bei mir auch Anfangs für eine gewisse Verwirrung gesorgt. Warum überhaupt kann das erste println das x außerhalb des Scopes sehen? Die println Anweisung findet das x oberhalb und das ist auch gewollt so. Es geht um das x innerhalb und außerhalb der Klammern. Das x, das sich quasi auf der main() Ebene befindet, ist nach Entstehung gültig, bis es "verbraucht/konsumiert" wurde. Das Einlesen gilt nicht als Konsum. Versuchen wir noch ein Beispiel mit einer Funktion, damit das deutlicher wird, auch wenn ich dabei einen Fehler erzwingen muss. Das muss ich unterteilen, damit es deutlicher sichtbar wird. Ich baue die erste Funktion ein, im weiteren Beispiel dann die 2te.

fn eating_var(a:String) ->String{
    println!("{}.Funktion eating_var hat deine Variable gefressen",a);
    let b = a;
    b
}
fn main(){

    let x = String::from("Variable x sagt: Ich bin eine unschuldige, jungfräuliche Variable. Friss mich bitte nicht //");
    eating_var(x);
}

Ausgabe

image.png

Wenn jetzt die Funktion where_var nach dem String Ausschau hält, wird es diesen nicht mehr finden.

fn eating_var(a:String) ->String{
    println!("{}.Funktion eating_var hat deine Variable gefressen",a);
    let b = a;
    b
}

fn where_var(a:String)->String{
    let c =a;
    println!("Funktion where_var kann die Variable nicht finden");
    c
}
fn main(){

    let x = String::from("Variable x sagt: Ich bin eine unschuldige, jungfräuliche Variable. Friss mich bitte nicht //");
    eating_var(x);
    where_var(x);   
}

Ausgabe

image.png

eating_var hat also den Besitz über die Variable übernommen, deshalb kann where_var, nicht mehr darauf zugreifen, außer eating_var würde von x ein clone() machen. Übrigens, werden primitive Datentypen, wie i32, als normales Copy übertragen. Der Wert des Originals bleibt aber dabei erhalten. Dann machen wir als nächstes wohl die

Referenzen
Da muss ich jetzt etwas ausholen. Man könnte sagen, Referenzen gibt es in verschiedenen Geschmacksrichtungen. Und trotzdem, ihr ahnt es schon, sind sie streng geregelt. Referenzen kann man sich am ehesten als so eine Art Zeiger, oder Verlinkung vorstellen, die man auch von Betriebssystemen kennt. Meistens unter dem Namen "Verknüpfung" bekannt. Die Referenz greift auf den Wert zu, sie besitzt ihn aber nicht. Ein bisschen wie so eine Art Fernsteuerung. Dabei gibt es eine

*immutable Referenz
und eine
*mutable Referenz

Die immutable Referenz darf nur lesen. Es können aber beliebig viele "Instanzen" einer solchen Referenz erstellt werden. Die mutable Referenz darf Lesen und Schreiben, aber es darf nur eine einzelne Instanz von ihr gleichzeitig exitieren. Keinesfalls dürfen immutable und mutable Referenzen auf den gleichen Wert zugreifen.

Schauen wir uns das mal genauer an und beginnen mit den standardisierten immutablen Referenzen. Standard deshalb, weil ohne Zugabe von mut eine Variable sowieso nicht veränderbar ist.

In diesem Fall trägt die Variable secret_var eine Geheimzahl und 3 nachfolgende Variablen haben Lesezugriff.

 let secret_var = String::from("Die geheime Zahl lautet 25");
    let ask_secret1=("ask_secret1 fragt nach der geheimen Zahl".to_string(), &secret_var);
    let ask_secret2=("ask_secret2 fragt nach der geheimen Zahl".to_string(), &secret_var);
    let ask_secret3=("ask_secret3 fragt nach der geheimen Zahl".to_string(), &secret_var);

    println!("{:?}\n{:?}\n{:?}\n",ask_secret1,ask_secret2,ask_secret3);

Ausgabe

image.png

Im übrigen erzeugt, wenn man das kaufmännische Und(Ampersand) aus der Formel rausnimmt, wieder den Fehler, man solle .clone() verwenden. Also der deutliche Hinweis, dass man den Wert nicht einfach so übernehmen kann.

Versuchen wir jetzt eine mutable Geheimzahl und schauen was passiert.

let mut secret_var = String::from("Die geheime Zahl lautet jetzt 13");
    let mut_ask_secret1=("mut_ask_secret1 fragt nach der geheimen Zahl".to_string(), &mut secret_var);
    println!("{:?}",mut_ask_secret1);
    //jetzt versuchen wir noch eine 2te mut Varialbe, die Geheimzahl abzufragen.
    let mut mut_ask_secret2=("mut_ask_secret2 fragt nach der geheimen Zahl".to_string(), &mut secret_var);
    println!("{:?}",mut_ask_secret2);
    //Das funktioniert auch. Jetzt wird mal die mut Variable die Geheime Zahl ändern.
    *mut_ask_secret2.1="Die geheime Zahl lautet jetzt 17".to_string();
    //Hier kann nur mut_ask_secret2 mit einem Stern davor, die Geheime Zahl ändern.
    //Vergleichen wir nun mut_ask_secret2 mit secret_var und eigentlich auch noch die 1er davon.
    // println!("secret_var{:?},mut_ask_secret1{:?},mut_ask_secret2{:?}",mut secret_var,mut_ask_secret1,mut_ask_secret2);
    //Das geht nicht, weil er nun doch weiß dass die mutable Variable öfters als 1x in Verwendung ist.
    //println!("{:?}",mut_ask_secret1); -> nicht erlaubt.
    println!("mut_ask_secret2={:?}",mut_ask_secret2); //Die 2er geht wie erwartet.
    println!("secret_var={:?}",secret_var); //Das geht auch. Original bleibt erhalten.

Ausgabe

image.png

Das war jetzt etwas komplizierter als erhofft. Vor allem wusste ich gerade nicht recht, wie ich mit den Fehlerinformationen umgehen soll, deshalb habe ich sie in die Kommentare gepackt. Es stimmt tatsächlich: 2 oder mehrere mut Variablen können/dürfen keine ändernde Referenz einer anderen, angefragten mut Variable sein. Und die Referenz ändert den Wert mit einem Stern davor.

Zu guter Letzt, widmen wir uns noch dem schon öfters erwähnten

.clone()

let clone_string=String::from("Ich bin ein Clone_String");
let copy_of_clone_string = clone_string.clone();
println!("copy_of_clone_string={:?}",copy_of_clone_string);

Ausgabe
image.png

und schon haben wir ein schönes Duplikat des Strings, ohne Meckern.

Jetzt raucht mir der Schädel!

Zum Schluss wieder die bekannte Zusammenfassung.

fn eating_var(a:String) ->String{
    println!("{}.Funktion eating_var hat deine Variable gefressen",a);
    let b = a;
    b
}

fn where_var(a:String)->String{
    let c =a;
    println!("Funktion where_var kann die Variable nicht finden");
    c
}
fn main(){
    //Shadowing
    let x = 1;
    println!("x1={}",x);
    let x = 2; // Das erste x wird "überschattet" und bekommt einen neuen Wert.
    println!("x2={}",x);

    //Scope = Geltungsbereich
    let x = 1;
    println!("x oberhalb der Klammern={}",x);
    {
        println!("x in der Klammern, BEVOR x in den Klammern definiert wurde={}",x);
        let x = 2;
        println!("x in der Klammern, NACHDEM x in den Klammern definiert wurde={}",x);

    }
    println!("x unterhalb der Klammer={}",x);

    //Scope - Lebensdauer - Funktion
    let x = String::from("Variable x sagt: Ich bin eine unschuldige, jungfräuliche Variable. Friss mich bitte nicht //");
    eating_var(x);
    // where_var(x);

    let secret_var = String::from("Die geheime Zahl lautet 25");
    let ask_secret1=("ask_secret1 fragt nach der geheimen Zahl".to_string(), &secret_var);
    let ask_secret2=("ask_secret2 fragt nach der geheimen Zahl".to_string(), &secret_var);
    let ask_secret3=("ask_secret3 fragt nach der geheimen Zahl".to_string(), &secret_var);

    println!("{:?}\n{:?}\n{:?}\n",ask_secret1,ask_secret2,ask_secret3);

    let mut secret_var = String::from("Die geheime Zahl lautet jetzt 13");
    let mut_ask_secret1=("mut_ask_secret1 fragt nach der geheimen Zahl".to_string(), &mut secret_var);
    println!("{:?}",mut_ask_secret1);
    //jetzt versuchen wir noch eine 2te mut Varialbe, die Geheimzahl abzufragen.
    let mut mut_ask_secret2=("mut_ask_secret2 fragt nach der geheimen Zahl".to_string(), &mut secret_var);
    println!("{:?}",mut_ask_secret2);
    //Das funktioniert auch. Jetzt wird mal die mut Variable die Geheime Zahl ändern.
    *mut_ask_secret2.1="Die geheime Zahl lautet jetzt 17".to_string();
    //Hier kann nur mut_ask_secret2 mit einem Stern davor, die Geheime Zahl ändern.
    //Vergleichen wir nun mut_ask_secret2 mit secret_var und eigentlich auch noch die 1er davon.
    // println!("secret_var{:?},mut_ask_secret1{:?},mut_ask_secret2{:?}",mut secret_var,mut_ask_secret1,mut_ask_secret2);
    //Das geht nicht, weil er nun doch weiß dass die mutable Variable öfters als 1x in Verwendung ist.
    //println!("{:?}",mut_ask_secret1); -> nicht erlaubt.
    println!("mut_ask_secret2={:?}",mut_ask_secret2); //Die 2er geht wie erwartet.
    println!("secret_var={:?}",secret_var); //Das geht auch.

    let clone_string=String::from("Ich bin ein Clone_String");
    let copy_of_clone_string = clone_string.clone();
    println!("copy_of_clone_string={:?}",copy_of_clone_string);

}


Ausgabe

image.png

vom Editor

18.png

PS.: Jetzt habe ich mal den gesamten Text hier der KI hier in Hive zum Fraß vorgeworfen, was da wohl für ein Bild rauskäme. Naja, es ist passend und ziemlich nüchtern, finde ich.

image.png

0.02769979 BEE
0 comments