diff --git a/lectures/Rust/src/basics.md b/lectures/Rust/src/basics.md index 1fd5086..3c6db1a 100644 --- a/lectures/Rust/src/basics.md +++ b/lectures/Rust/src/basics.md @@ -31,8 +31,11 @@ Variables in Rust are declared with the `let` keyword (thanks FP). ```rust,editable fn main() { - let answer : u64 = 42; - println!("The answer to life the universe and everything is {}.", answer); + let answer: u64 = 42; + println!( + "The answer to life the universe and everything is {}.", + answer + ); } ``` @@ -47,9 +50,15 @@ Let's look at what happens when we try to change the value of `answer`. ```rust,editable fn main() { let answer = 42; - println!("The answer to life the universe and everything is {}.", answer); + println!( + "The answer to life the universe and everything is {}.", + answer + ); answer = 41; - println!("I changed my mind. The answer to life the universe and everything is {}.", answer); + println!( + "I changed my mind. The answer to life the universe and everything is {}.", + answer + ); } ``` @@ -60,10 +69,15 @@ The following works fine. ```rust,editable fn main() { let mut answer = 42; - println!("The answer to life the universe and everything is {}.", answer); + println!( + "The answer to life the universe and everything is {}.", + answer + ); answer = 41; - println!("I changed my mind. The answer to life the universe and everything is {}.", answer); - + println!( + "I changed my mind. The answer to life the universe and everything is {}.", + answer + ); } ``` @@ -111,7 +125,7 @@ Snippet from the Rust book: ```rust, editable fn main() { let c = 'z'; - let z : char = 'ℤ'; // with explicit type annotation + let z: char = 'ℤ'; // with explicit type annotation let heart_eyed_cat = '😻'; } ``` @@ -123,18 +137,18 @@ fn main() { ```rust,editable fn main() { - // constructing tuples - let t : (u64, f32, char) = (42, 10.0, 'z'); + // constructing tuples + let t: (u64, f32, char) = (42, 10.0, 'z'); - println!("My tuple is {:?}", t); + println!("My tuple is {:?}", t); - // eliminating tuples: projection - println!("The first component is {}", t.0); + // eliminating tuples: projection + println!("The first component is {}", t.0); - // eliminating tuples: decomposition pattern - let (x, y, z) = t; + // eliminating tuples: decomposition pattern + let (x, y, z) = t; - println!("The first component is {}", x); + println!("The first component is {}", x); } ``` @@ -151,9 +165,9 @@ type is fixed and statically known. They are allocated on the stack. ```rust,editable fn main() { - let a : [u32;5]= [1,2,3,4,5]; + let a: [u32; 5] = [1, 2, 3, 4, 5]; - println!("The 2nd element is {}", a[1]); + println!("The 2nd element is {}", a[1]); } ``` @@ -167,14 +181,14 @@ The following program compiles fine and throws an error at runtime. You can also see an example of Rust function (yes, arrows again). ```rust,editable -fn access(a : [u32;5], n : usize) -> u32{ - return a[n]; +fn access(a: [u32; 5], n: usize) -> u32 { + return a[n]; } fn main() { - let a : [u32;5]= [1,2,3,4,5]; + let a: [u32; 5] = [1, 2, 3, 4, 5]; - println!("The 2nd element is {}", access(a, 7)); + println!("The 2nd element is {}", access(a, 7)); } ``` @@ -190,42 +204,40 @@ Here are some examples of Rust functions. ```rust,editable -fn fourtytwo() -> u32{ - return 42; +fn fourtytwo() -> u32 { + return 42; } fn sayhi() { - println!("Hello!"); + println!("Hello!"); } -fn add(x: u32, y:u32) -> u32{ - x+y +fn add(x: u32, y: u32) -> u32 { + x + y } fn main() { - println!("One more time {}", fourtytwo()); - - sayhi(); + println!("One more time {}", fourtytwo()); - println!("Add two numbers: {}", add(5,6)); + sayhi(); + println!("Add two numbers: {}", add(5, 6)); } ``` We can declare function parameters as mutable. ```rust,editable -fn add1(mut t : (u32, u32)) -> u32 { +fn add1(mut t: (u32, u32)) -> u32 { t.0 += 1; return t.0; } fn main() { - let mut t = (1,2); + let mut t = (1, 2); println!("add1 result: {}", add1(t)); println!("The first component is {}", t.0); - } ``` @@ -237,66 +249,67 @@ Book](https://doc.rust-lang.org/book/ch03-05-control-flow.html). ```rust,editable - -fn fib(n : u32) -> u32 { - if n == 0 { 0 } - else if n == 1 { 1 } - else { fib(n-1) + fib(n-2) } +fn fib(n: u32) -> u32 { + if n == 0 { + 0 + } else if n == 1 { + 1 + } else { + fib(n - 1) + fib(n - 2) + } } - -fn fib_iter1(n : u32) -> u32 { +fn fib_iter1(n: u32) -> u32 { let mut i = n; let mut curr = 0; let mut next = 1; loop { - let tmp = curr; - curr = next; - next = next + tmp; - i-=1; - if i == 0 { break curr } + let tmp = curr; + curr = next; + next = next + tmp; + i -= 1; + if i == 0 { + break curr; + } } } -fn fib_iter2(n : u32) -> u32 { +fn fib_iter2(n: u32) -> u32 { let mut i = n; let mut curr = 0; let mut next = 1; while i != 0 { - let tmp = curr; - curr = next; - next = next + tmp; - i-=1; + let tmp = curr; + curr = next; + next = next + tmp; + i -= 1; } return curr; } -fn fib_iter3(n : u32) -> u32 { +fn fib_iter3(n: u32) -> u32 { let mut i = n; let mut curr = 0; let mut next = 1; for i in 0..n { - let tmp = curr; - curr = next; - next = next + tmp; + let tmp = curr; + curr = next; + next = next + tmp; } return curr; } - fn main() { + let n = 8; - let n = 8; - - println!("Functional: The {}th fib is: {}", n, fib(n)); - println!("Iterative 1: The {}th fib is: {}", n, fib_iter1(n)); - println!("Iterative 2: The {}th fib is: {}", n, fib_iter2(n)); - println!("Iterative 3: The {}th fib is: {}", n, fib_iter3(n)); - + println!("Functional: The {}th fib is: {}", n, fib(n)); + println!("Iterative 1: The {}th fib is: {}", n, fib_iter1(n)); + println!("Iterative 2: The {}th fib is: {}", n, fib_iter2(n)); + println!("Iterative 3: The {}th fib is: {}", n, fib_iter3(n)); } -``` \ No newline at end of file +``` diff --git a/lectures/Rust/src/generics.md b/lectures/Rust/src/generics.md index 00d2e45..7fb75e5 100644 --- a/lectures/Rust/src/generics.md +++ b/lectures/Rust/src/generics.md @@ -9,7 +9,7 @@ functionality that is common to all types. A very simple example of a polymorphic function is the identity function. ```rust,editable -fn id(x:T) -> T { +fn id(x: T) -> T { x } @@ -26,12 +26,12 @@ Function can be generic over more than one types. This is illustrated in the following example. ```rust,editable -fn make_tuple(x:T, y:R) -> (T,R) { +fn make_tuple(x: T, y: R) -> (T, R) { (x, y) } fn main() { - println!("{:?}", make_tuple(42,11)); + println!("{:?}", make_tuple(42, 11)); } ``` @@ -46,10 +46,10 @@ The example also illustrates macros in Rust. #[derive(Debug)] enum List { Nil, - Cons(T, Box>) + Cons(T, Box>), } -use List::{Cons,Nil}; // To be able to use Cons and Nil without qualifying them. +use List::{Cons, Nil}; // To be able to use Cons and Nil without qualifying them. // Define some macros for lists macro_rules! list { @@ -69,14 +69,12 @@ macro_rules! list { }; } - impl List { - // return a reference to the head of the list (if any) or nothing fn head(&self) -> Option<&T> { match self { Nil => None, - Cons(x,_) => Some(x) + Cons(x, _) => Some(x), } } @@ -87,7 +85,7 @@ impl List { while let Cons(value, mut next) = current { current = *next; // Move to the next node - *next = rev ; // Reverse the link + *next = rev; // Reverse the link rev = Cons(value, next); // Update the reversed list } @@ -101,17 +99,17 @@ impl List { fn length(&self) -> u64 { match self { Nil => 0, - Cons(_,l) => 1 + l.length() + Cons(_, l) => 1 + l.length(), } } } fn main() { - let mut l = list![1,2,3]; + let mut l = list![1, 2, 3]; l.rev(); - println!{"{:?}",l} + println!("{:?}",l); } ``` diff --git a/lectures/Rust/src/iterators.md b/lectures/Rust/src/iterators.md index cd36660..1141edf 100644 --- a/lectures/Rust/src/iterators.md +++ b/lectures/Rust/src/iterators.md @@ -31,7 +31,10 @@ pub struct Counter { impl Counter { /// Creates a new Counter iterator. pub fn new(start: i32, end: i32) -> Self { - Counter { current: start, end } + Counter { + current: start, + end, + } } } @@ -55,7 +58,7 @@ fn main() { let counter = Counter::new(1, 5); // the for ... in ... construct can be used to iterate over an iterator. - for value in counter { + for value in counter { println!("{}", value); } } @@ -78,7 +81,6 @@ the `IntoIterator` trait for a type. This has the following definition. ```rust, ignore pub trait IntoIterator { - type Item; // associated types for iterator item type IntoIter: Iterator; // associated iterator type @@ -122,7 +124,7 @@ fn main() { let mut numbers = vec![1, 2, 3]; // Using IntoIterator for &mut Vec - let iter_mut = numbers.iter_mut(); // Equivalent to (&mut numbers).into_iter(); + let iter_mut = numbers.iter_mut(); // Equivalent to (&mut numbers).into_iter(); for num in iter_mut { *num += 1; } @@ -134,7 +136,11 @@ fn main() { ### Owned Values ```rust, editable fn main() { - let names = vec!["alice".to_string(), "bob".to_string(), "charlie".to_string()]; + let names = vec![ + "alice".to_string(), + "bob".to_string(), + "charlie".to_string(), + ]; // Create a new vector to hold the transformed values let mut uppercase_names = Vec::new(); @@ -165,12 +171,11 @@ fn main() { // Write some closures let closure_annotated = |x: i32, y: i32| -> i32 { x + y + outer_var }; - let closure_inferred = |x, y| { x + y + outer_var }; + let closure_inferred = |x, y| x + y + outer_var; // Call the closures - println!("closure_annotated: {}", closure_annotated(1,2)); - println!("closure_inferred: {}", closure_inferred(3,4)); - + println!("closure_annotated: {}", closure_annotated(1, 2)); + println!("closure_inferred: {}", closure_inferred(3, 4)); } ``` @@ -178,12 +183,10 @@ Note that closures cannot be polymorphic. The following example fails. ```rust,editable fn main() { - - let id = |x| { x }; + let id = |x| x; println!("Call 1: {}", id("hello")); println!("Call 2: {}", id(3)); - } ``` @@ -244,8 +247,10 @@ Here's the above example, adapted so that it compiles. ```rust, editable // `F` must be generic. -fn apply(f: F) -where F : Fn() -> () { +fn apply(f: F) +where + F: Fn() -> (), +{ f(); } @@ -268,13 +273,14 @@ Here's an example from the standard library ```rust, editable fn main() { - let a = vec![1, 2, 3]; + let a = vec![1, 2, 3]; + + let doubled: Vec = a + .iter() // convert vec into an iterator + .map(|&x| x * 2) // call map + .collect(); // reconstruct an iterator - let doubled: Vec = a.iter() // convert vec into an iterator - .map(|&x| x * 2) // call map - .collect(); // reconstruct an iterator - - println!("{:?}", doubled) + println!("{:?}", doubled) } ``` @@ -288,8 +294,7 @@ fn main() { let numbers = vec![1, 2, 3, 4, 5, 6]; // Use fold to calculate the sum of all elements - let sum = numbers.iter() - .fold(0, |acc, &x| acc + x); + let sum = numbers.iter().fold(0, |acc, &x| acc + x); println!("Sum: {}", sum); // Output: Sum: 21 } @@ -301,9 +306,7 @@ fn main() { let numbers = vec![1, 2, 3, 4, 5, 6]; // Filter out only even numbers and collect them into a new vector - let even_numbers: Vec = numbers.into_iter() - .filter(|&x| x % 2 == 0) - .collect(); + let even_numbers: Vec = numbers.into_iter().filter(|&x| x % 2 == 0).collect(); println!("Even numbers: {:?}", even_numbers); // Output: [2, 4, 6] } diff --git a/lectures/Rust/src/lifetimes.md b/lectures/Rust/src/lifetimes.md index fe11130..ef336e9 100644 --- a/lectures/Rust/src/lifetimes.md +++ b/lectures/Rust/src/lifetimes.md @@ -12,11 +12,10 @@ the borrow end before the lifetime of the variable `z`. ```rust, editable fn main() { - let z : &Box<(u32,u32)>; + let z: &Box<(u32, u32)>; { - - let y : Box<(u32,u32)> = Box::new((42, 44)); + let y: Box<(u32, u32)> = Box::new((42, 44)); z = &y; } // y's lifetime ends here. y is dropped. @@ -34,18 +33,16 @@ fn first(a: &T, b: &T) -> &T { } fn main() { - let x : Box<(u32,u32)> = Box::new((32, 34)); + let x: Box<(u32, u32)> = Box::new((32, 34)); - let z : &Box<(u32,u32)>; + let z: &Box<(u32, u32)>; { - let y : Box<(u32,u32)> = Box::new((42, 44)); - - z = first(&x,&y); + let y: Box<(u32, u32)> = Box::new((42, 44)); + z = first(&x, &y); } // y's lifetime ends here. y is dropped. - println!("{:?}", z) } ``` @@ -68,23 +65,21 @@ relationships between the lifetimes of the function's inputs and output ```rust, editable -fn first<'a,'b,T>(x: &'a T, y: &'b T) -> &'a T { +fn first<'a, 'b, T>(x: &'a T, y: &'b T) -> &'a T { x } fn main() { - let x : Box<(u32,u32)> = Box::new((32, 34)); + let x: Box<(u32, u32)> = Box::new((32, 34)); - let z : &Box<(u32,u32)>; + let z: &Box<(u32, u32)>; { - let y : Box<(u32,u32)> = Box::new((42, 44)); - - z = first(&x,&y); + let y: Box<(u32, u32)> = Box::new((42, 44)); + z = first(&x, &y); } // y's lifetime ends here - println!("{:?}", z) } ``` @@ -108,7 +103,7 @@ reference held in `z` after the return is valid at the time of printing it. The function `first` could have been also given the following type: ```rust, ignore -fn first<'a,T>(x: &'a T, y: &'a T) -> &'a T { +fn first<'a, T>(x: &'a T, y: &'a T) -> &'a T { x } ``` @@ -124,21 +119,24 @@ lifetime of the returned reference must be the smaller of the two lifetimes. As an exercise, try to fill in the lifetimes in the example below. ```rust, editable -fn longer(v1:&Vec, v2: &Vec) -> &Vec { - if v1.len() >= v2.len() { v1 } else { v2 } +fn longer(v1: &Vec, v2: &Vec) -> &Vec { + if v1.len() >= v2.len() { + v1 + } else { + v2 + } } fn main() { - let x : Vec = vec![1,2,3,4]; + let x: Vec = vec![1, 2, 3, 4]; - let z : &Vec; + let z: &Vec; { - let y : Vec = vec![1,2,3]; + let y: Vec = vec![1, 2, 3]; - z = longer(&x,&y); + z = longer(&x, &y); println!("{:?}", z) - } // println!("{:?}", z) @@ -193,7 +191,6 @@ fn main() { read_write: read_write, }; - println!("Sum of read-only part: {}", sum(&chunks)); zero_out(&mut chunks); @@ -205,24 +202,23 @@ fn main() { Here is an example where it is useful for struct fields to have distinct lifetimes. ```rust, editable -struct Chunks<'a,'b, T> { +struct Chunks<'a, 'b, T> { read: &'a [T], read_write: &'b mut [T], } -fn zero_out<'a,'b>(chunks: &mut Chunks<'a,'b, u32>) { +fn zero_out<'a, 'b>(chunks: &mut Chunks<'a, 'b, u32>) { for i in 0..chunks.read_write.len() { chunks.read_write[i] = 0; } } - fn main() { let mut v1 = vec![1, 2, 3, 4, 5]; let s; { - let v2 = vec![6,7,8]; + let v2 = vec![6, 7, 8]; let mut chunks = Chunks { read: &v2[1..3], @@ -232,12 +228,10 @@ fn main() { zero_out(&mut chunks); s = chunks.read_write; - } - println!("Slice: {:?}", s); - println!("After zero_out: {:?}", v1); - + println!("Slice: {:?}", s); + println!("After zero_out: {:?}", v1); } ``` @@ -266,7 +260,8 @@ struct Example { impl Example { // The method get_value borrows self and returns a reference to its value. // The lifetime of &self is inferred to be the same as the returned reference. - fn get_value(&self) -> &i32 { // same as get_value<'a>(&'a self) -> &'a i32 + fn get_value(&self) -> &i32 { + // same as get_value<'a>(&'a self) -> &'a i32 &self.value } } @@ -353,5 +348,4 @@ fn main() { // The slice can be used throughout the program println!("Static slice from leak: {:?}", data); } - -``` \ No newline at end of file +``` diff --git a/lectures/Rust/src/moretypes.md b/lectures/Rust/src/moretypes.md index 1575db0..afe587d 100644 --- a/lectures/Rust/src/moretypes.md +++ b/lectures/Rust/src/moretypes.md @@ -17,8 +17,10 @@ struct Point { } fn add(a: Point, b: Point) -> Point { - Point { x : a.x + b.x, - y : a.y + b.y } + Point { + x: a.x + b.x, + y: a.y + b.y, + } } fn main() { @@ -54,14 +56,16 @@ struct TwoPoints(Point, Point); fn add(ps: TwoPoints) -> Point { let TwoPoints(pA, pB) = ps; // tuple structs can be pattern matched - return (Point { x : pA.x + pB.x, - y : pA.y + pA.y, // dot notation also works - z : pA.z + pB.z }); + return (Point { + x: pA.x + pB.x, + y: pA.y + pA.y, // dot notation also works + z: pA.z + pB.z, + }); } fn main() { let pointA = Point { x: 0, y: 0, z: 0 }; - let pointB = Point { y: 5, .. pointA}; // this is called "update syntax" + let pointB = Point { y: 5, ..pointA }; // this is called "update syntax" let both = TwoPoints(pointA, pointB); @@ -69,7 +73,6 @@ fn main() { println!("The points are {:?}", both); println!("Its sum is {:?}", add(both)); - } ``` @@ -100,22 +103,24 @@ impl Point { // distance from origin fn dist0(&self) -> f64 { // converts to f64 and calculares the square root - ((self.x^2 + self.y^2) as f64).sqrt() + ((self.x ^ 2 + self.y ^ 2) as f64).sqrt() } // distance from any point - fn dist(&self, p : Point) -> f64 { + fn dist(&self, p: Point) -> f64 { // converts to f64 and calculares the square root - (((self.x - p.x)^2 + (self.y - p.y)^2) as f64).sqrt() + (((self.x - p.x) ^ 2 + (self.y - p.y) ^ 2) as f64).sqrt() } // add two points - fn add (&self, p : Point) -> Point { - Point { x : self.x + self.x, - y : self.y + self.y } + fn add(&self, p: Point) -> Point { + Point { + x: self.x + self.x, + y: self.y + self.y, + } } - fn moveUp (&mut self) { + fn moveUp(&mut self) { self.y += 1 } } @@ -146,12 +151,11 @@ Here's an illustrative example. enum Shape { Circle(f64), Rectangle { width: f64, height: f64 }, - Triangle(f64, f64, f64) + Triangle(f64, f64, f64), } impl Shape { fn area(&self) -> f64 { - match self { // Circle Shape::Circle(radius) => std::f64::consts::PI * radius.powi(2), @@ -169,7 +173,10 @@ impl Shape { fn main() { let circle = Shape::Circle(3.0); - let rectangle = Shape::Rectangle { width: 4.0, height: 5.0 }; + let rectangle = Shape::Rectangle { + width: 4.0, + height: 5.0, + }; let triangle = Shape::Triangle(3.0, 4.0, 5.0); println!("Area of the circle: {}", circle.area()); @@ -193,7 +200,7 @@ enum OpKind { Add, Sub, Mul, - Div + Div, } #[derive(Debug)] @@ -203,8 +210,8 @@ enum Exp { } fn main() { - let e = Lit(42); - println!("{}", e); + let e = Lit(42); + println!("{}", e); } ``` @@ -231,7 +238,7 @@ the heap and places the given value into it. ```rust, editable fn main() { - let b : Box = Box::new(1); + let b: Box = Box::new(1); println!("The number is {}", b); } ``` @@ -246,44 +253,51 @@ enum Op { Add, Sub, Mul, - Div + Div, } #[derive(Debug)] enum Exp { Lit(i64), - Op { op: Op, lhs: Box, rhs: Box }, + Op { + op: Op, + lhs: Box, + rhs: Box, + }, } impl Exp { - fn eval(&self) -> i64 { match self { // Literals Exp::Lit(n) => *n, // TODO why is this &i64 // Binary Operators - Exp::Op {op, lhs, rhs} => { - let e1 = lhs.eval(); - let e2 = rhs.eval(); - match op { - Op::Add => e1 + e2, - Op::Sub => e1 - e2, - Op::Mul => e1 * e2, - Op::Div => e1 / e2 - } + Exp::Op { op, lhs, rhs } => { + let e1 = lhs.eval(); + let e2 = rhs.eval(); + match op { + Op::Add => e1 + e2, + Op::Sub => e1 - e2, + Op::Mul => e1 * e2, + Op::Div => e1 / e2, + } } } } } fn main() { - // e = 10 + 2 * 6 - let e = Exp::Op{ op: Op::Add, - lhs: Box::new(Exp::Lit(10)), - rhs: Box::new(Exp::Op { op: Op::Mul, - lhs: Box::new(Exp::Lit(2)), - rhs: Box::new(Exp::Lit(6)) } ) }; - - println!("The answer is {}", e.eval()); + // e = 10 + 2 * 6 + let e = Exp::Op { + op: Op::Add, + lhs: Box::new(Exp::Lit(10)), + rhs: Box::new(Exp::Op { + op: Op::Mul, + lhs: Box::new(Exp::Lit(2)), + rhs: Box::new(Exp::Lit(6)), + }), + }; + + println!("The answer is {}", e.eval()); } -``` \ No newline at end of file +``` diff --git a/lectures/Rust/src/ownership.md b/lectures/Rust/src/ownership.md index 4bde1c3..fedd78c 100644 --- a/lectures/Rust/src/ownership.md +++ b/lectures/Rust/src/ownership.md @@ -10,20 +10,17 @@ One can create a tuple, pass it to a function to compute the sum of its components, and then continue using the original tuple afterward: ```rust, editable - -fn addt(t : (u32,u32)) -> u32 { +fn addt(t: (u32, u32)) -> u32 { t.0 + t.1 } fn main() { - - let t = (3,4); + let t = (3, 4); println!("The sum is: {}", addt(t)); println!("The first component is: {}", t.0); } - ``` Nothing unusual about that; we do this all the time in various programming @@ -66,7 +63,7 @@ additional fields to track its length and capacity. ```rust, editable -fn main () { +fn main() { let mut vec = Vec::new(); // calling the constructor vec.push(1); @@ -77,19 +74,19 @@ fn main () { println!("The length of the vector is {}", vec.len()); println!("The second element is {}", vec[1]); - // vec goes out of scope here. The rust compiler can safely drop the value. + // vec goes out of scope here. The rust compiler can safely drop the value. } - ``` Let's write a function to sum the elements of a vector. ```rust, editable -fn sum (v : Vec) -> u32 { +fn sum(v: Vec) -> u32 { let mut sum = 0; - for i in 0..v.len() { // 0 <= i < v.len() - 1. + for i in 0..v.len() { + // 0 <= i < v.len() - 1. sum += v[i] } @@ -99,8 +96,7 @@ fn sum (v : Vec) -> u32 { // Once v goes out of scope the value can be dropped. } - -fn main () { +fn main() { let mut vec = Vec::new(); // calling the constructor vec.push(1); @@ -121,10 +117,11 @@ terminology. Consider the following example, where we attempt to use vec after calling sum: ```rust, editable -fn sum (v : Vec) -> u32 { +fn sum(v: Vec) -> u32 { let mut sum = 0; - for i in 0..v.len() { // 0 <= i < v.len() - 1. + for i in 0..v.len() { + // 0 <= i < v.len() - 1. sum += v[i] } return sum; @@ -133,8 +130,7 @@ fn sum (v : Vec) -> u32 { // v.iter().sum() } - -fn main () { +fn main() { let mut vec = Vec::new(); // calling the constructor vec.push(1); @@ -163,7 +159,7 @@ Likewise, if you assign `vec` to another variable, the same move semantics apply—ownership is transferred, and the original variable can no longer be used. ```rust, editable -fn main () { +fn main() { let mut vec = Vec::new(); // calling the constructor vec.push(1); @@ -188,20 +184,20 @@ ownership of the value and can continue using it. ```rust, editable -fn sum (v : Vec) -> (u32, Vec) { +fn sum(v: Vec) -> (u32, Vec) { let mut sum = 0; - for i in 0..v.len() { // 0 <= i < v.len() - 1. + for i in 0..v.len() { + // 0 <= i < v.len() - 1. sum += v[i] } - return (sum,v); + return (sum, v); // or just: // v.iter().sum() } - -fn main () { +fn main() { let mut vec1 = Vec::new(); // calling the constructor vec1.push(1); @@ -216,7 +212,6 @@ fn main () { let (sum2, _) = sum(vec2); println!("The sum of the elements of the vector is {:?}", sum2); - } ``` @@ -230,24 +225,22 @@ Note that in order for the function parameter to take ownership of a vector and mutate it, we must declare the function parameter as mutable. ```rust, editable -fn add_one(mut v : Vec) -> Vec { - +fn add_one(mut v: Vec) -> Vec { // That's not idiomatic Rust. We will learn how to do this with iterators. - for i in 0..v.len() { // 0 <= i < v.len() - 1. + for i in 0..v.len() { + // 0 <= i < v.len() - 1. v[i] += 1 } return v; } - -fn main () { - let mut vec = vec![1,2,3]; +fn main() { + let mut vec = vec![1, 2, 3]; let v = add_one(vec); println!("The vector is {:?}", v); - } ``` @@ -275,4 +268,4 @@ Another common heap allocated type in Rust is strings. Rust has a type `str` that .... -a growable, mutable, owned, UTF-8 encoded string type \ No newline at end of file +a growable, mutable, owned, UTF-8 encoded string type diff --git a/lectures/Rust/src/references.md b/lectures/Rust/src/references.md index 64bdfbb..4dbe459 100644 --- a/lectures/Rust/src/references.md +++ b/lectures/Rust/src/references.md @@ -21,10 +21,10 @@ Let's look at some simple examples of references. We will start with references to stack allocated values. ```rust, editable -fn main () { - let mut x : u32 = 42; +fn main() { + let mut x: u32 = 42; // get a reference to x - let r : &u32 = &x; + let r: &u32 = &x; println!("Hello, it is {} again.", r); } @@ -33,8 +33,8 @@ fn main () { Multiple immutable references can coexist at the same time. For example: ```rust, editable -fn main () { - let mut x : u32 = 42; +fn main() { + let mut x: u32 = 42; // get two references to x let r1 = &x; let r2 = &x; @@ -52,10 +52,10 @@ is not declared as a mutable reference. To do this, we have to declare the reference as mutable. ```rust, editable -fn main () { - let mut x : u32 = 41; +fn main() { + let mut x: u32 = 41; // take a mutable reference of x - let r : &mut u32 = &mut x; + let r: &mut u32 = &mut x; *r += 1; println!("Hello, it is {} again.", r); } @@ -69,24 +69,24 @@ access the memory it points at. The following code snippets all fail to compile. ```rust, editable -fn main () { - let mut x : u32 = 41; +fn main() { + let mut x: u32 = 41; // take a mutable reference of x - let r : &mut u32 = &mut x; + let r: &mut u32 = &mut x; *r += 1; // take a reference of x. NO NO. - let r2 : &u32 = &x; + let r2: &u32 = &x; println!("Hello, it is {} again.", r); } ``` ```rust, editable -fn main () { - let mut x : u32 = 41; +fn main() { + let mut x: u32 = 41; // take a mutable reference of x - let r : &mut u32 = &mut x; + let r: &mut u32 = &mut x; // take a second mutable reference of x. BIG NO. - let r2 : &mut u32 = &mut x; + let r2: &mut u32 = &mut x; *r += 1; println!("Hello, it is {} again.", r); } @@ -96,9 +96,9 @@ While the value of `x` is mutably borrowed we are not able to access the value through the owner. The following snippet also fails to compile. ```rust, editable -fn main () { - let mut x : u32 = 41; - let r : &mut u32 = &mut x; +fn main() { + let mut x: u32 = 41; + let r: &mut u32 = &mut x; *r += 1; println!("Hello, it is {} again.", x); println!("Hello, it is {} again.", r); @@ -118,9 +118,9 @@ ensuring safe concurrent programming. Notice that the following works just fine. Can you imagine why? ```rust, editable -fn main () { - let mut x : u32 = 41; - let r : &mut u32 = &mut x; +fn main() { + let mut x: u32 = 41; + let r: &mut u32 = &mut x; *r += 1; println!("Hello, it is {} again.", x); } @@ -131,14 +131,14 @@ The lifetime of a borrow ends then the borrow is last used. In this example, thi Similarly, the following examples work fine. ```rust, editable -fn main () { - let mut x : u32 = 40; +fn main() { + let mut x: u32 = 40; - let r1 : &mut u32 = &mut x; // r1's lifetime begins here + let r1: &mut u32 = &mut x; // r1's lifetime begins here *r1 += 1; println!("{}.", r1); // r1's lifetime ends here - let r2 : &mut u32 = &mut x; // r2's lifetime begins here + let r2: &mut u32 = &mut x; // r2's lifetime begins here *r2 += 1; println!("Hello, it is {} again.", r2); // r2's lifetime ends here } @@ -148,14 +148,14 @@ In the above the lifetimes of `r1` and `r2` do not overlap. The following exampl ```rust, editable -fn main () { - let mut x : u32 = 40; +fn main() { + let mut x: u32 = 40; - let r1 : &mut u32 = &mut x; // r1's lifetime begins here + let r1: &mut u32 = &mut x; // r1's lifetime begins here *r1 += 1; println!("{}.", r1); // r1's lifetime ends here - let r2 : &u32 = &x; // r2's lifetime begins here + let r2: &u32 = &x; // r2's lifetime begins here println!("Still {}.", r2); // r2's lifetime ends here } ``` @@ -180,13 +180,14 @@ pointers. Here are the rules: Here's an example of trying to create a reference whose lifetime would outlive the lifetime of the owner. ```rust, editable -fn nope<'a>() -> &'a u32 { // 'a is a lifetime variable. We'll discuss this later in detail. You may ignore it for now. - let x = 42; - return &x; // attempting to return a reference to x +fn nope<'a>() -> &'a u32 { + // 'a is a lifetime variable. We'll discuss this later in detail. You may ignore it for now. + let x = 42; + return &x; // attempting to return a reference to x } fn main() { - println!("Will this work? {}", nope()); + println!("Will this work? {}", nope()); } ``` @@ -205,16 +206,16 @@ lifetime of the variables creates within the scope ends. ```rust, editable fn main() { - let mut x = 40; + let mut x = 40; - { - let z = &mut x; - *z += 1; - } // z's lifetime ends here + { + let z = &mut x; + *z += 1; + } // z's lifetime ends here - let y = &mut x; - *y += 1; - println!("Hello, it is {} again.", x); + let y = &mut x; + *y += 1; + println!("Hello, it is {} again.", x); } ``` @@ -223,35 +224,33 @@ prevent borrows that outlive the scope of the owner ```rust, editable fn main() { - let x : &mut u32; - - { - let mut z = 41; - x = &mut z; + let x: &mut u32; - } // z's lifetime ends here + { + let mut z = 41; + x = &mut z; + } // z's lifetime ends here - *x += 1; - println!("Hello, it is {} again.", x); + *x += 1; + println!("Hello, it is {} again.", x); } ``` However, the following works fine. ```rust, editable fn main() { - let mut x : &mut u32; - - { - let mut z = 41; - x = &mut z; - println!("Hello, it is {} again.", x); - - } // z's lifetime ends here - - let mut y = 10; - x = &mut y; - *x += 1; - println!("Hello, now it is {}.", x); + let mut x: &mut u32; + + { + let mut z = 41; + x = &mut z; + println!("Hello, it is {} again.", x); + } // z's lifetime ends here + + let mut y = 10; + x = &mut y; + *x += 1; + println!("Hello, now it is {}.", x); } ``` @@ -264,16 +263,18 @@ use reference to make it easier. ```rust, editable -fn sum (v : &Vec) -> u32 { // sum takes a reference to the vector. +fn sum(v: &Vec) -> u32 { + // sum takes a reference to the vector. let mut sum = 0; - for i in 0..v.len() { // 0 <= i < v.len() - 1. + for i in 0..v.len() { + // 0 <= i < v.len() - 1. sum += v[i] } return sum; } -fn main () { +fn main() { let mut vec = Vec::new(); // calling the constructor vec.push(1); @@ -296,23 +297,20 @@ fn main () { The following example showcases passing a mutable reference to a vector as a parameter. ```rust, editable -fn add_one(v : &mut Vec) { - +fn add_one(v: &mut Vec) { // That's not idiomatic Rust. We will learn how to do this with iterators. - for i in 0..v.len() { // 0 <= i < v.len() - 1. + for i in 0..v.len() { + // 0 <= i < v.len() - 1. v[i] += 1 } } - -fn main () { - - let mut vec = vec![1,2,3]; +fn main() { + let mut vec = vec![1, 2, 3]; add_one(&mut vec); println!("The vector is {:?}", vec); - } ``` @@ -324,10 +322,10 @@ fn main() { let mut x = &data[0]; println!("{}", x); - + data.push(4); x = &data[3]; println!("{}", x); } -``` \ No newline at end of file +``` diff --git a/lectures/Rust/src/traits.md b/lectures/Rust/src/traits.md index 71b818d..451cca3 100644 --- a/lectures/Rust/src/traits.md +++ b/lectures/Rust/src/traits.md @@ -162,9 +162,11 @@ fn compare_areas(shape1: &T, shape2: &U) -> String { } fn main() { - let circle = Circle { radius: 5.0 }; - let rectangle = Rectangle { width: 4.0, height: 6.0 }; + let rectangle = Rectangle { + width: 4.0, + height: 6.0, + }; println!("Comparison: {}", compare_areas(&circle, &rectangle)); } @@ -217,7 +219,6 @@ fn main() { // Display output println!("{}", p); } - ``` ### `Debug` @@ -262,7 +263,6 @@ fn main() { // Debug output, pretty printed println!("{:#?}", triangle); - } ``` @@ -304,7 +304,6 @@ fn main() { // Debug output, pretty printed println!("{:#?}", triangle); - } ``` @@ -333,10 +332,10 @@ clone even is `T` is not). #[derive(Debug, Clone)] enum List { Nil, - Cons(T, Box>) + Cons(T, Box>), } -use List::{Cons,Nil}; // To be able to use Cons and Nil without qualifying them. +use List::{Cons, Nil}; // To be able to use Cons and Nil without qualifying them. // Define some macros for lists macro_rules! list { @@ -358,21 +357,22 @@ macro_rules! list { fn main() { // Create a cons list: 1 -> 2 -> 3 -> Nil - let mut list1 = list![1,2,3]; + let mut list1 = list![1, 2, 3]; // Perform a deep copy of the list let list2 = list1.clone(); - list1 = { match list1 { - Nil => Nil, - Cons(_, rest) => Cons(42, rest) } - }; + list1 = { + match list1 { + Nil => Nil, + Cons(_, rest) => Cons(42, rest), + } + }; // Print both lists to verify they are independent println!("Original list: {:?}", list1); println!("Cloned list: {:?}", list2); } - ``` A manual implementation for `Clone` in the above would be: @@ -398,7 +398,7 @@ ownership rules. ```rust, editable fn main() { - let mut x = (1,3); + let mut x = (1, 3); let x1 = x.1; x.1 = 42; @@ -431,7 +431,7 @@ handled automatically by the compiler whenever a value is assigned or passed. In fact, the `Copy` trait itself does not define any methods. Its definition is: ```rust, ignore -pub trait Copy: Clone { } +pub trait Copy: Clone {} ``` This means that any type implementing `Copy` must also implement the `Clone` @@ -454,25 +454,28 @@ Notice the difference in the following snippets. The second fails to compile. ```rust, editable #[derive(Debug)] -struct AStruct<'a,T,R> { - x : T, - y : &'a R +struct AStruct<'a, T, R> { + x: T, + y: &'a R, } -impl<'a,T,R> Clone for AStruct<'a,T,R> -where T : Clone { +impl<'a, T, R> Clone for AStruct<'a, T, R> +where + T: Clone, +{ fn clone(&self) -> Self { - AStruct { x : self.x.clone() - , y : self.y.clone() } + AStruct { + x: self.x.clone(), + y: self.y.clone(), + } } } -impl<'a,T,R> Copy for AStruct<'a,T,R> -where T : Copy { } +impl<'a, T, R> Copy for AStruct<'a, T, R> where T: Copy {} fn main() { - let v = vec![1,2,3]; - let mut s : AStruct> = AStruct { x : 42 , y : &v }; + let v = vec![1, 2, 3]; + let mut s: AStruct> = AStruct { x: 42, y: &v }; let mut z = s; // copy s @@ -485,14 +488,14 @@ fn main() { ```rust, editable #[derive(Debug, Clone, Copy)] -struct AStruct<'a,T,R> { - x : T, - y : &'a R +struct AStruct<'a, T, R> { + x: T, + y: &'a R, } fn main() { - let v = vec![1,2,3]; - let s : AStruct> = AStruct { x : 42 , y : &v }; + let v = vec![1, 2, 3]; + let s: AStruct> = AStruct { x: 42, y: &v }; let mut z = s; // copy s diff --git a/lectures/Rust/src/typestate.md b/lectures/Rust/src/typestate.md index 62d1c91..798f4c0 100644 --- a/lectures/Rust/src/typestate.md +++ b/lectures/Rust/src/typestate.md @@ -78,16 +78,16 @@ impl User { } fn main() { - let mut user = User::new("admin".to_string(),"password".to_string()); + let mut user = User::new("admin".to_string(), "password".to_string()); let mut secret; - match user.authenticate() { + match user.authenticate() { Ok(user) => secret = user.get_top_secret(), Err(_) => secret = "cannot read secret", - } + } - println!("{}", secret); + println!("{}", secret); } ``` -## A More Complex Example \ No newline at end of file +## A More Complex Example