mirror of
https://github.com/LukasKalbertodt/programmieren-in-rust.git
synced 2025-06-29 00:07:31 +02:00
Rename sheet folders to assure proper sorting
This commit is contained in:
5
aufgaben/sheet06/README.md
Executable file
5
aufgaben/sheet06/README.md
Executable file
@ -0,0 +1,5 @@
|
||||
Blatt 6
|
||||
=======
|
||||
|
||||
Dreimal dürft ihr raten: Diese Aufgaben sollen auf dem Branch `sheet6`
|
||||
bearbeitet werden, der von dem `master`-Branch entsprungen ist!
|
6
aufgaben/sheet06/sol1/Cargo.toml
Executable file
6
aufgaben/sheet06/sol1/Cargo.toml
Executable file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "sol1"
|
||||
version = "0.1.0"
|
||||
authors = ["Lukas Kalbertodt <lukas.kalbertodt@gmail.com>"]
|
||||
|
||||
[dependencies]
|
52
aufgaben/sheet06/sol1/src/lib.rs
Executable file
52
aufgaben/sheet06/sol1/src/lib.rs
Executable file
@ -0,0 +1,52 @@
|
||||
use std::ops::{Add, Mul};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
||||
/// Clamps a value into a given range. This function returns the value closest
|
||||
/// to `value` which lies in between `min` and `max`.
|
||||
///
|
||||
/// *Note*: it's not clear whether `PartialOrd` or `Ord` is the correct bound
|
||||
/// here. With `PartialEq`, some results may look strange to some.
|
||||
/// `clamp(NaN, 0.0, 5.0)` would return `NaN` for example. `NaN` as min or max
|
||||
/// wouldn't do anything.
|
||||
pub fn clamp<T>(value: T, min: T, max: T) -> T
|
||||
where T: PartialOrd
|
||||
{
|
||||
// This is a small little trick. We want to avoid using if-else here, so
|
||||
// we match the unit value `()` (void) and use the match guards.
|
||||
match () {
|
||||
() if value < min => min,
|
||||
() if value > max => max,
|
||||
_ => value,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Returns the sum and the product of the two given parameters.
|
||||
///
|
||||
/// *Note*: Either a Clone or Copy bound is necessary. Clone was choosen here,
|
||||
/// because it's more general.
|
||||
pub fn sum_product<T, U>(a: T, b: U)
|
||||
-> (<T as Add<U>>::Output, <T as Mul<U>>::Output)
|
||||
where T: Add<U> + Mul<U> + Clone,
|
||||
U: Clone
|
||||
{
|
||||
(a.clone() + b.clone(), a * b)
|
||||
}
|
||||
|
||||
/// Extension trait for simple conversion from `bool` to `Option<T>`
|
||||
pub trait BoolOptionExt {
|
||||
/// If `self` is `true`, `Some(value)` is returned, `None` otherwise.
|
||||
fn into_option<T>(self, value: T) -> Option<T>;
|
||||
}
|
||||
|
||||
impl BoolOptionExt for bool {
|
||||
fn into_option<T>(self, value: T) -> Option<T> {
|
||||
match self {
|
||||
true => Some(value),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
28
aufgaben/sheet06/sol1/src/tests.rs
Executable file
28
aufgaben/sheet06/sol1/src/tests.rs
Executable file
@ -0,0 +1,28 @@
|
||||
#[test]
|
||||
fn clamp() {
|
||||
use clamp;
|
||||
|
||||
assert_eq!(clamp(3, 5, 10), 5);
|
||||
assert_eq!(clamp(6, 5, 10), 6);
|
||||
assert_eq!(clamp(11, 5, 10), 10);
|
||||
|
||||
assert_eq!(clamp(3.0, 5.0, 10.0), 5.0);
|
||||
assert_eq!(clamp(6.0, 5.0, 10.0), 6.0);
|
||||
assert_eq!(clamp(11.0, 5.0, 10.0), 10.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sum_product() {
|
||||
use sum_product;
|
||||
|
||||
assert_eq!(sum_product(3, 4), (7, 12));
|
||||
assert_eq!(sum_product(3.0, 4.0), (7.0, 12.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bool_option() {
|
||||
use BoolOptionExt;
|
||||
|
||||
assert_eq!(false.into_option(3), None);
|
||||
assert_eq!( true.into_option(3), Some(3));
|
||||
}
|
7
aufgaben/sheet06/sol2/Cargo.toml
Executable file
7
aufgaben/sheet06/sol2/Cargo.toml
Executable file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "sol2"
|
||||
version = "0.1.0"
|
||||
authors = ["Lukas Kalbertodt <lukas.kalbertodt@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
num-traits = "0.1"
|
59
aufgaben/sheet06/sol2/src/lib.rs
Executable file
59
aufgaben/sheet06/sol2/src/lib.rs
Executable file
@ -0,0 +1,59 @@
|
||||
extern crate num_traits;
|
||||
|
||||
use num_traits::{Zero, One};
|
||||
use std::ops;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub struct Vector2<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
}
|
||||
|
||||
impl<T> Vector2<T> {
|
||||
pub fn new(x: T, y: T) -> Self {
|
||||
Vector2 {
|
||||
x: x,
|
||||
y: y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zero> Vector2<T> {
|
||||
pub fn origin() -> Self {
|
||||
Self::new(T::zero(), T::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zero + One> Vector2<T> {
|
||||
pub fn unit_x() -> Self {
|
||||
Self::new(T::one(), T::zero())
|
||||
}
|
||||
|
||||
pub fn unit_y() -> Self {
|
||||
Self::new(T::zero(), T::one())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ops::Add<Vector2<U>> for Vector2<T>
|
||||
where T: ops::Add<U>
|
||||
{
|
||||
type Output = Vector2<T::Output>;
|
||||
|
||||
fn add(self, rhs: Vector2<U>) -> Self::Output {
|
||||
Vector2::new(self.x + rhs.x, self.y + rhs.y)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ops::Mul<U> for Vector2<T>
|
||||
where T: ops::Mul<U>,
|
||||
U: Clone
|
||||
{
|
||||
type Output = Vector2<T::Output>;
|
||||
|
||||
fn mul(self, rhs: U) -> Self::Output {
|
||||
Vector2::new(self.x * rhs.clone(), self.y * rhs)
|
||||
}
|
||||
}
|
18
aufgaben/sheet06/sol2/src/tests.rs
Executable file
18
aufgaben/sheet06/sol2/src/tests.rs
Executable file
@ -0,0 +1,18 @@
|
||||
use Vector2;
|
||||
|
||||
#[test]
|
||||
fn constructors() {
|
||||
assert_eq!(Vector2::new(27, 42), Vector2 { x: 27, y: 42 });
|
||||
assert_eq!(Vector2::origin(), Vector2 { x: 0, y: 0 });
|
||||
assert_eq!(Vector2::unit_x(), Vector2 { x: 1, y: 0 });
|
||||
assert_eq!(Vector2::unit_y(), Vector2 { x: 0, y: 1 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn operators() {
|
||||
let a = Vector2::new(3, 7);
|
||||
let b = Vector2::new(-2, 5);
|
||||
|
||||
assert_eq!(a + b, Vector2::new(1, 12));
|
||||
assert_eq!(a * 2, Vector2::new(6, 14));
|
||||
}
|
27
aufgaben/sheet06/sol3/swagger.rs
Executable file
27
aufgaben/sheet06/sol3/swagger.rs
Executable file
@ -0,0 +1,27 @@
|
||||
use std::fmt;
|
||||
|
||||
struct Swagger<T>(pub T);
|
||||
|
||||
impl<T: fmt::Display> fmt::Display for Swagger<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(f, "yolo {} swag", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
trait SwaggerExt: Sized {
|
||||
fn with_swag(self) -> Swagger<Self>;
|
||||
}
|
||||
|
||||
impl<T> SwaggerExt for T {
|
||||
fn with_swag(self) -> Swagger<Self> {
|
||||
Swagger(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let pi = 3.14;
|
||||
|
||||
println!("{}", pi);
|
||||
println!("{}", Swagger(pi));
|
||||
println!("{}", pi.with_swag());
|
||||
}
|
41
aufgaben/sheet06/task1/README.md
Executable file
41
aufgaben/sheet06/task1/README.md
Executable file
@ -0,0 +1,41 @@
|
||||
Aufgabe 1: Hilfsfunktionen
|
||||
==========================
|
||||
|
||||
In dieser Aufgabe soll eine Library-Crate (Cargo Projekt) erstellt werden,
|
||||
welche ein paar kleine, aber nützliche Funktionalitäten bereitstellt.
|
||||
|
||||
Für alle drei Funktionen/Methoden soll ein Unittest geschrieben werden. Alle
|
||||
Unittests liegen in dem `tests` Untermodul der Crate; alles andere kann aber
|
||||
im Wurzelmodul definiert sein. *Hinweis*: Mit `cargo test` können alle
|
||||
Unittests ausgeführt werden.
|
||||
|
||||
|
||||
### a) `clamp()`
|
||||
|
||||
Diese Funktion nimmt drei Parameter: einen Wert sowie `min` und `max`.
|
||||
Die Funktion returned einfach den gegebenen Wert, solange er zwischen `min` und
|
||||
`max` liegt. Falls der gegebene Wert jedoch kleiner als `min` ist, wird `min`
|
||||
returned; das gleiche entsprechend mit `max`.
|
||||
|
||||
Die Funktion soll so allgemein wie möglich formuliert werden und keine
|
||||
genauen Typen festlegen.
|
||||
|
||||
|
||||
### b) Summe und Produkt
|
||||
|
||||
Die Funktion nimmt zwei Argumente and und liefert sowohl die Summe als auch
|
||||
das Produkt dieser beiden Werte zurück. Auch diese Funktion soll möglichst
|
||||
allgemein formuliert werden.
|
||||
|
||||
|
||||
### c) Extension Trait
|
||||
|
||||
Wir würden gerne `bool`-Variablen sehr einfach in ein `Option<T>` umwandeln
|
||||
können, also z.B. so einen Code aufrufen können:
|
||||
|
||||
```rust
|
||||
true.into_option(3); // Some(3)
|
||||
false.into_option("susi"); // None
|
||||
```
|
||||
|
||||
Fügt die Methode zu `bool` mit Hilfe eines Extension Traits hinzu.
|
36
aufgaben/sheet06/task2/README.md
Executable file
36
aufgaben/sheet06/task2/README.md
Executable file
@ -0,0 +1,36 @@
|
||||
Aufgabe 2: Vektor
|
||||
=================
|
||||
|
||||
In dieser Aufgabe soll ein einfacher, generischer Vektor-Typ erstellt werden.
|
||||
Wieder soll eine Library-Crate als Cargo-Projekt angelegt werden und im `tests`
|
||||
Untermodul sollen ein paar kurze Unittests die eigentliche Funktionalität
|
||||
testen.
|
||||
|
||||
Der Datentyp soll `Vector2` heißen und besteht aus einer x- und y-Koordinate.
|
||||
Der Typ dieser Koordinaten ist jedoch generisch und kann grundsätzlich erstmal
|
||||
alles sein. Neben den expliziten Anforderungen in a) und b) kann und/oder
|
||||
muss `Vector2` noch weitere Traits implementieren, solange das möglich ist.
|
||||
|
||||
|
||||
### a) Konstruktor-Funktionen
|
||||
|
||||
Wir möchten vier Konstruktor-Funktionen zu `Vector2` hinzufügen:
|
||||
|
||||
- `new(x, y)`: bekommt beide Koordinaten als Parameter
|
||||
- `origin()`: Vektor am Nullpunkt (beide Koordinaten 0)
|
||||
- `unit_x()`: Ein Einheitsvektor mit x=1
|
||||
- `unit_y()`: Ein Einheitsvektor mit y=1
|
||||
|
||||
Um diese Funktionen implementieren zu können, greifen wir auf schon vorhandene
|
||||
Traits zu. Diese finden wir in der Crate `num-traits`, die es wie gewohnt auf
|
||||
crates.io gibt. Von dieser externen Bibliothek müsst ihr euch passende Traits,
|
||||
die ihr nutzen wollt/müsst, aussuchen (wir sind nur an den Traits der
|
||||
Bibliothek interessiert!).
|
||||
|
||||
|
||||
### b) Operatoren überladen
|
||||
|
||||
Für den Vektor soll der `+` und `*` Operator überladen werden (wenn dies
|
||||
möglich ist).
|
||||
Dabei ist das eine natürlich die Vektoraddition (also Vektor + Vektor), das
|
||||
andere ist die Skalarmultiplikation (also Vektor * Skalar).
|
21
aufgaben/sheet06/task3/README.md
Executable file
21
aufgaben/sheet06/task3/README.md
Executable file
@ -0,0 +1,21 @@
|
||||
Aufgabe 3: Swagger
|
||||
==================
|
||||
|
||||
*Diese Aufgabe kann in einer einzelnen `.rs` Datei gelöst werden und benötigt
|
||||
kein Cargo-Projekt.*
|
||||
|
||||
Erstellt einen Typ `Swagger`, welcher einen beliebigen anderen Typen in sich
|
||||
speichert.
|
||||
`Swagger` soll mit `println!()` und dem normalen `{}` Platzhalter
|
||||
ausgegeben werden können, wenn immer das möglich ist.
|
||||
Die Ausgabe soll "yolo ??? swag" sein, wobei "???" für die Ausgabe des inneren
|
||||
Objekts steht.
|
||||
Wäre also eine `3` in einer Swagger-Instanz gespeichert und man würde diese
|
||||
Instanz ausgeben, wäre die Ausgabe "yolo 3 swag".
|
||||
|
||||
Weiterhin soll es möglich sein, auf jedem beliebigen Typen direkt eine Methode
|
||||
`with_swag()` aufzurufen, die diesen Typen in eine `Swagger`-Instanz verpackt.
|
||||
|
||||
```
|
||||
println!("{}", 3.with_swag()); // prints: "yolo 3 swag"
|
||||
```
|
Reference in New Issue
Block a user