Rust structs
This commit is contained in:
parent
8ea9552f8f
commit
b9430effb8
171
diaries/rust/05 - Structs.adoc
Normal file
171
diaries/rust/05 - Structs.adoc
Normal file
@ -0,0 +1,171 @@
|
||||
:experimental:
|
||||
:docdatetime: 2022-07-05T17:31:22+02:00
|
||||
|
||||
= Structs
|
||||
|
||||
https://doc.rust-lang.org/book/ch05-00-structs.html[Link zum Buch]
|
||||
|
||||
== Was sind Structs
|
||||
|
||||
Structs kennt man ja aus C/C++.
|
||||
Man kann es (denke ich) auch mit JavaScript Objekten vergleichen.
|
||||
|
||||
In Structs gruppiert man zusammengehöriges Zeug und hat so eine Art Pseudo-OOP.
|
||||
Man kann damit neue Datentypen machen.
|
||||
|
||||
== How to
|
||||
|
||||
=== "Normale" Structs
|
||||
|
||||
[source, Rust]
|
||||
----
|
||||
struct User {
|
||||
active: bool,
|
||||
username: String,
|
||||
email: String,
|
||||
sign_in_count: u64,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut user1 = User {
|
||||
email: String::from("someone@example.com"),
|
||||
username: String::from("someusername123"),
|
||||
active: true,
|
||||
sign_in_count: 1,
|
||||
};
|
||||
|
||||
println!("{}", user1.email);
|
||||
|
||||
user1.email = String::from("anotheremail@example.com");
|
||||
}
|
||||
----
|
||||
|
||||
Hinweis: Es können nicht einzelne Felder mutable sein, sondern wenn dann immer das ganze Struct.
|
||||
|
||||
==== Dinge wie in Javascript
|
||||
Wenn die Variable heißt wie das Feld, kann man auch statt `email: email` einfach nur `email` schreiben.
|
||||
|
||||
Wenn man ein neues Struct aus einem alten mit Updates erstellen will, geht das auch mit einer Art Spread-Parameter:
|
||||
|
||||
[source, Rust]
|
||||
----
|
||||
let user2 = User {
|
||||
email: String::from("another@example.com"),
|
||||
..user1
|
||||
};
|
||||
----
|
||||
|
||||
`..user1` *muss* als letztes kommen und füllt dann alle bisher nicht gesetzten Felder.
|
||||
Außerdem ist das etwas tricky:
|
||||
Wenn die Daten, die von `user1` zu `user2` übertragen werden, gemoved werden (sprich: keine primitiven Datentypen sind), dann ist `user1` danach ungültig.
|
||||
Hätten wir jetzt auch noch einen neuen `username` gesetzt (auch ein String) und nur `active` und `sign_in_count` übertragen, wäre `user1` noch gültig.
|
||||
|
||||
=== Tupel Structs
|
||||
|
||||
[source, Rust]
|
||||
----
|
||||
struct RGBColor(u8, u8, u8);
|
||||
|
||||
fn main() {
|
||||
let black = Color(0, 0, 0)
|
||||
}
|
||||
----
|
||||
|
||||
Sind nutzbar wie Tupel (destrucuture und `.index` zum Zugriff auf Werte), allerdings eben ein eigener Typ.
|
||||
|
||||
=== Unit-Like Structs
|
||||
|
||||
[source, Rust]
|
||||
----
|
||||
struct AlwaysEqual;
|
||||
----
|
||||
|
||||
Ein Struct muss keine Felder haben.
|
||||
Das Buch meint, man könnte für diesen Datentypen jetzt noch Traits implementieren, aber davon habe ich noch keine Ahnung.
|
||||
Nur dann macht diese Art von Struct irgendwie Sinn.
|
||||
|
||||
== Ownership der Felder
|
||||
|
||||
Im ersten Beispiel wird `String` satt `&str` genutzt.
|
||||
Wir wollen am besten im Struct keine Referenzen, oder es müssen "named lifetime parameter" sein, etwas das wir erst später lernen.
|
||||
Der Compiler wird sonst streiken.
|
||||
|
||||
== Das erste Mal Traits
|
||||
|
||||
Im Buch folgt ein Beispielprogramm für ein Struct, das ein Rechteck abbildet.
|
||||
Wir wollten das ganze printen (mit `{}` als Platzhalter), allerdings implementiert Das Rechteck nicht `std::fmt::Display`.
|
||||
Das scheint eine Art `toString()` für Rust zu sein.
|
||||
|
||||
Es gibt aber noch eine andere Möglichkeit und das haben wir schonmal für Tupel genutzt:
|
||||
`{:?}` als Platzhalter (bzw. `{:#?}` für pretty print).
|
||||
Dafür brauchen wir aber das Trait `Debug`.
|
||||
Zum Glück scheint das aber einfach zu implementieren sein, es muss nur implementiert werden.
|
||||
|
||||
Der Compiler schlägt uns zwei Varianten vor:
|
||||
|
||||
1. `#[derive(Debug)]` über der Definition des Structs
|
||||
2. `impl Debug for Rectangle` manuell
|
||||
|
||||
Jetzt können wir Variablen dieses Typs printen und es zeigt uns Datentyp und Felder an.
|
||||
|
||||
Alternativ kann man auch das Makro `dbg!(...)` nutzen.
|
||||
Das wird dann auf `stderr` geprintet.
|
||||
Man kann sogar ein Statement da rein packen (also zum Beispiel `30 * x`) und bekommt das Statement mit dem Ergebnis geprintet, wobei das Ergebnis (als Wert, nicht Referenz) auch zurückgegeben wird.
|
||||
|
||||
== Funktionen in Structs
|
||||
|
||||
Unser Struct soll jetzt auch eine Funktion auf sich selbst aufrufen können.
|
||||
Tatsächlich ist der sehr einfach und sehr OOPig.
|
||||
|
||||
Die folgenden Beispiele sollten relativ viel erklären.
|
||||
|
||||
[source, Rust]
|
||||
----
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl Rectangle {
|
||||
// var.area();
|
||||
fn area(&self) -> u32 {
|
||||
self.width * self.height
|
||||
}
|
||||
|
||||
// Rectangle::square(5);
|
||||
fn square(size: u32) -> Rectangle {
|
||||
Rectangle {
|
||||
width: size,
|
||||
height: size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mehrere impl Blöcke sind erlaubt
|
||||
impl Rectangle {
|
||||
// var.has_same_area(&other);
|
||||
fn has_same_area(&self, other: &Rectangle) -> bool {
|
||||
self.area() == other.area()
|
||||
}
|
||||
|
||||
// Rectangle::same_area(&first, &second);
|
||||
fn same_area(first: &Rectangle, second: &Rectangle) -> bool {
|
||||
first.area() == second.area()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rect1 = Rectangle {
|
||||
width: 12,
|
||||
height: 3,
|
||||
};
|
||||
let rect2 = Rectangle::square(6);
|
||||
|
||||
println!("{}", rect1.area()); // 36
|
||||
println!("{}", rect2.area()); // 36
|
||||
|
||||
println!("{}", rect1.has_same_area(&rect2)); // true
|
||||
println!("{}", rect2.has_same_area(&rect1)); // true
|
||||
println!("{}", Rectangle::same_area(&rect1, &rect2)); // true
|
||||
}
|
||||
----
|
@ -40,7 +40,8 @@
|
||||
{ "title": "01 - Cargo", "filename": "01 - Cargo"},
|
||||
{ "title": "02 - Higher-Lower-Game", "filename": "02 - Higher-Lower-Spiel"},
|
||||
{ "title": "03 - Cheatsheet", "filename": "03 - Concepts"},
|
||||
{ "title": "04 - Ownership", "filename": "04 - Ownership"}
|
||||
{ "title": "04 - Ownership", "filename": "04 - Ownership"},
|
||||
{ "title": "05 - Structs", "filename": "05 - Structs"}
|
||||
]
|
||||
},
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user