feat(arrived at types)
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "rust-by-example"
|
||||
version = "0.1.0"
|
||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "rust-by-example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
231
src/customtypes.rs
Normal file
231
src/customtypes.rs
Normal file
@@ -0,0 +1,231 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub fn custom_types_module() {
|
||||
// struct
|
||||
// 1. Tuple structs, basically named tuples
|
||||
struct Pair(i32, i32);
|
||||
let pair = Pair(1, 2);
|
||||
let Pair(_int1, _int2) = pair; // tuple structs can be destructured
|
||||
|
||||
// 2. C structs
|
||||
struct Point {
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
struct Polygon<'a, T> {
|
||||
points: [Point; 1],
|
||||
sliced_points: &'a [T],
|
||||
}
|
||||
|
||||
let point_top: Point = Point { x: 1.0, y: 1.0 };
|
||||
let point_list: [Point; 2] = [Point { x: 2.0, y: 3.0 }, Point { x: 3.0, y: 4.0 }];
|
||||
|
||||
let _point_borrow: Point = Point {
|
||||
x: 6.0,
|
||||
..point_top
|
||||
};
|
||||
|
||||
let _my_triangle = Polygon {
|
||||
points: [point_top],
|
||||
sliced_points: &point_list,
|
||||
};
|
||||
|
||||
// 3. Unit structs, field-less, useful for generics
|
||||
// 0 bytes of size, useful as markers and indicate variants
|
||||
struct Unit;
|
||||
let _unit = Unit;
|
||||
|
||||
/*
|
||||
impl Something for Unit {
|
||||
...
|
||||
}
|
||||
*/
|
||||
|
||||
// EXERCISE 1: create a triangle struct and a rect_area function, use nested destruturing
|
||||
#[derive(Debug, Clone)] // to allow printing, and cloning, last one with a performace loss
|
||||
struct MyPoint {
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
fn distance(a: MyPoint, b: MyPoint) -> f32 {
|
||||
return ((b.x - a.x).powf(2.0) + (b.y - a.y).powf(2.0)).sqrt();
|
||||
}
|
||||
|
||||
struct Rectangle {
|
||||
corners: [MyPoint; 4],
|
||||
}
|
||||
|
||||
fn rect_area(rect: Rectangle) -> f32 {
|
||||
let Rectangle { corners } = rect;
|
||||
|
||||
for i in 0..corners.len() {
|
||||
println!("Corner {}: {:?}", i, corners[i])
|
||||
}
|
||||
|
||||
return distance(corners[0].clone(), corners[1].clone())
|
||||
* distance(corners[0].clone(), corners[2].clone());
|
||||
}
|
||||
|
||||
let my_rectangle = Rectangle {
|
||||
corners: [
|
||||
MyPoint { x: 0.0, y: 0.0 },
|
||||
MyPoint { x: 4.0, y: 0.0 },
|
||||
MyPoint { x: 0.0, y: 4.0 },
|
||||
MyPoint { x: 4.0, y: 4.0 },
|
||||
],
|
||||
};
|
||||
|
||||
let my_rectangle_area = rect_area(my_rectangle);
|
||||
println!("My rectangle area: {}", my_rectangle_area);
|
||||
|
||||
// EXERCISE 2: create a function that returns a square out of a point
|
||||
fn square(p: MyPoint, size: f32) -> Rectangle {
|
||||
return Rectangle {
|
||||
corners: [
|
||||
MyPoint { x: p.x, y: p.y }, // don't know yet how to use borrowing properly
|
||||
MyPoint {
|
||||
x: p.x + size,
|
||||
y: p.y,
|
||||
},
|
||||
MyPoint {
|
||||
x: p.x,
|
||||
y: p.y + size,
|
||||
},
|
||||
MyPoint {
|
||||
x: p.x + size,
|
||||
y: p.y + size,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
let my_square = square(MyPoint { x: 0.0, y: 0.0 }, 2.0);
|
||||
|
||||
println!("My square: ");
|
||||
for i in 0..my_square.corners.len() {
|
||||
match my_square.corners.get(i) {
|
||||
Some(xval) => print!("{:?}", xval),
|
||||
None => println!("You went too far"),
|
||||
}
|
||||
}
|
||||
|
||||
// enum
|
||||
// ill make literally the example on rust-by-example
|
||||
enum WebEvent {
|
||||
PageLoad,
|
||||
PageUnload,
|
||||
Click { x: i64, y: i64 },
|
||||
}
|
||||
|
||||
fn inspect_web_event(event: WebEvent) {
|
||||
match event {
|
||||
// switch over the enum
|
||||
WebEvent::PageLoad => println!("Page loaded"),
|
||||
WebEvent::PageUnload => println!("Page unload"),
|
||||
WebEvent::Click { x, y } => println!("clicked at {}, {}", x, y),
|
||||
}
|
||||
}
|
||||
|
||||
let load = WebEvent::PageLoad;
|
||||
let unload = WebEvent::PageUnload;
|
||||
let click = WebEvent::Click { x: 20, y: 0 };
|
||||
|
||||
inspect_web_event(load);
|
||||
inspect_web_event(unload);
|
||||
inspect_web_event(click);
|
||||
|
||||
// enums can be used over a type alias
|
||||
type MyEventType = WebEvent;
|
||||
|
||||
let another_click = MyEventType::Click { x: 0, y: 20 };
|
||||
inspect_web_event(another_click);
|
||||
|
||||
// can also use "use crate::" to avoid manual scoping
|
||||
use WebEvent::{Click, PageUnload};
|
||||
|
||||
let yet_another_click = Click { x: 10, y: 0 };
|
||||
let another_unload = PageUnload;
|
||||
inspect_web_event(yet_another_click);
|
||||
inspect_web_event(another_unload);
|
||||
|
||||
// c-like enums
|
||||
enum Number {
|
||||
// implicit start at 0
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
}
|
||||
enum Color {
|
||||
Red = 0xff0000,
|
||||
Green = 0x00ff00,
|
||||
Blue = 0x0000ff,
|
||||
}
|
||||
|
||||
println!("zero is {}", Number::Zero as i32);
|
||||
println!("one is {}", Number::One as i32);
|
||||
|
||||
println!("roses are #{:06x}", Color::Red as i32);
|
||||
println!("violets are #{:06x}", Color::Blue as i32);
|
||||
|
||||
// Linked list implemented with enums
|
||||
|
||||
enum List {
|
||||
Cons(u32, Box<List>), // tuple struct with an element (u32) and a pointer to the next (Box<List>)
|
||||
Nil,
|
||||
}
|
||||
|
||||
impl List {
|
||||
// attach methods to the enum
|
||||
fn new() -> List {
|
||||
Self::Nil
|
||||
}
|
||||
|
||||
fn prepend(self, elem: u32) -> List {
|
||||
Self::Cons(elem, Box::new(self))
|
||||
}
|
||||
|
||||
fn stringify(&self) -> String {
|
||||
match *self {
|
||||
Self::Cons(head, ref tail) => {
|
||||
format!("{} {}", head, tail.stringify()) // recursive
|
||||
}
|
||||
Self::Nil => {
|
||||
format!("Nil / End")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut my_list = List::new();
|
||||
|
||||
my_list = my_list.prepend(1);
|
||||
my_list = my_list.prepend(2);
|
||||
my_list = my_list.prepend(3);
|
||||
my_list = my_list.prepend(4);
|
||||
my_list = my_list.prepend(5);
|
||||
|
||||
println!("My linked list: {}", my_list.stringify());
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MyNewPoint<T> {
|
||||
x: i32,
|
||||
y: T,
|
||||
}
|
||||
|
||||
let my_custom_point = MyNewPoint { x: 20, y: 10 };
|
||||
println!("A T type point {:?}", my_custom_point);
|
||||
|
||||
// consts
|
||||
const MYCONST: i32 = 10;
|
||||
//static : possibly mutable variable with 'static lifetime
|
||||
static MYSTATIC: &str = "Rust";
|
||||
|
||||
let a_number = 5;
|
||||
println!(
|
||||
"{} is {}",
|
||||
a_number,
|
||||
if a_number > MYCONST { "big" } else { "small" }
|
||||
);
|
||||
}
|
||||
128
src/helloworld.rs
Normal file
128
src/helloworld.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
pub fn hello_world_module() {
|
||||
// Basic arguments
|
||||
println!(
|
||||
"{0} {1} {exclamation_argument} {exclamation_argument}",
|
||||
"Hello",
|
||||
"world",
|
||||
exclamation_argument = "!"
|
||||
);
|
||||
|
||||
// Numeric arguments formating
|
||||
println!("Base 10 {}", 261);
|
||||
println!("Base 2 (binary) {:b}", 261);
|
||||
println!("Base 8 (octal) {:0}", 261);
|
||||
println!("Base 16 (hexadecimal) {:x}", 261);
|
||||
|
||||
// Justify text
|
||||
println!("{text:>10}", text = "right");
|
||||
println!("{text:0>10}", text = "right");
|
||||
println!("{text:<10}", text = "left");
|
||||
println!("{text:0<width$}", text = "left", width = 10);
|
||||
|
||||
// With actual variables
|
||||
let number: usize = 5;
|
||||
let another: usize = 2;
|
||||
println!("{number} {another}");
|
||||
|
||||
// Print structure types: fmt::Debug and "{:#?}"
|
||||
#[derive(Debug)]
|
||||
struct Person<'a> {
|
||||
name: &'a str,
|
||||
age: u8,
|
||||
}
|
||||
|
||||
let peter = Person {
|
||||
name: "Peter",
|
||||
age: 20,
|
||||
};
|
||||
println!("{:#?}", peter);
|
||||
|
||||
// A better way of printing structured data is by customizing the outputm with fmt::Display
|
||||
// this code should not be inside main nor a function, but will keep it here to maintain a sequential order
|
||||
use std::fmt; // import the fmt module
|
||||
|
||||
// NOTE: if you want to avoid writing fmt::... every time, it can also be destructured in the
|
||||
// import: use std::fmt::{self, Formatter, Display};
|
||||
|
||||
struct Structure(i32);
|
||||
|
||||
// implement the fmt::Display in order to use the {} marker
|
||||
impl fmt::Display for Structure {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "My structure formated: {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
let my_structure = Structure(1);
|
||||
println!("{}", my_structure);
|
||||
|
||||
// Display list example
|
||||
// we'll use the ? operator:
|
||||
// write!(f, "{}", value)?;
|
||||
// Explanation: try to run write!, if it errors return the error, otherwise continue
|
||||
// This is the proper way of handling the posible error what return fmt::Result (returned by
|
||||
// the write!()
|
||||
struct List(Vec<i32>);
|
||||
|
||||
impl fmt::Display for List {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// Extract the value using tuple indexing,
|
||||
// and create a reference to `vec`.
|
||||
let vec = &self.0;
|
||||
|
||||
write!(f, "[")?;
|
||||
|
||||
// Iterate over `v` in `vec` while enumerating the iteration
|
||||
// count in `count`.
|
||||
for (count, v) in vec.iter().enumerate() {
|
||||
// For every element except the first, add a comma.
|
||||
// Use the ? operator to return on errors.
|
||||
if count != 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{}: {}", count, v)?;
|
||||
}
|
||||
|
||||
// Close the opened bracket and return a fmt::Result value.
|
||||
write!(f, "]")
|
||||
}
|
||||
}
|
||||
|
||||
let v = List(vec![1, 2, 3]);
|
||||
println!("{}", v);
|
||||
|
||||
// Formating can be specified via traits, there is one trait for each argument type (b,x,o,X,
|
||||
// ...)
|
||||
// The default argument {} is formated with the Display trait
|
||||
|
||||
struct City {
|
||||
name: &'static str,
|
||||
lat: f32,
|
||||
lon: f32,
|
||||
}
|
||||
|
||||
impl fmt::Display for City {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let lat_c = if self.lat >= 0.0 { 'N' } else { 'S' };
|
||||
let lon_c = if self.lon >= 0.0 { 'E' } else { 'W' };
|
||||
|
||||
write!(
|
||||
f,
|
||||
"{}: {:.3}°{} {:.3}°{}",
|
||||
self.name,
|
||||
self.lat.abs(),
|
||||
lat_c,
|
||||
self.lon.abs(),
|
||||
lon_c
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let salamanca = City {
|
||||
name: "Salamanca",
|
||||
lat: 53.34778,
|
||||
lon: -6.259722,
|
||||
};
|
||||
|
||||
println!("{}", salamanca)
|
||||
}
|
||||
20
src/main.rs
Normal file
20
src/main.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
// normal comment
|
||||
/*
|
||||
* Multi-line comment
|
||||
*/
|
||||
// : /// Doc comment: generate library docs for the following item
|
||||
// : //! Doc comment
|
||||
|
||||
//mod helloworld;
|
||||
//mod primitives;
|
||||
//mod customtypes;
|
||||
//mod variablebindings;
|
||||
mod types;
|
||||
|
||||
fn main() {
|
||||
//helloworld::hello_world_module();
|
||||
//primitives::primitives_module();
|
||||
//customtypes::custom_types_module();
|
||||
//variablebindings::variable_bindings_module();
|
||||
types::types_module();
|
||||
}
|
||||
124
src/primitives.rs
Normal file
124
src/primitives.rs
Normal file
@@ -0,0 +1,124 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn reverse_tuple(pair: (i32, bool)) -> (bool, i32) {
|
||||
let (int_param, bool_param) = pair;
|
||||
|
||||
(bool_param, int_param)
|
||||
}
|
||||
|
||||
pub fn primitives_module() {
|
||||
// Scalar types
|
||||
// signed integers: i8, i16, i132, 164, i128
|
||||
// signed integers: u8, u16, u132, u64, u128
|
||||
// floating point: f32, f64
|
||||
// char
|
||||
// bool
|
||||
// unit type (), only posible value is an empty tuple
|
||||
////
|
||||
// Compound types
|
||||
// Array [1,2,3]
|
||||
// Tuples (1, true)
|
||||
|
||||
let logical = true; // not necesary to specify the type if initialized
|
||||
let a_float: f64 = 1.0;
|
||||
let rare_integer = 5i32; // suffix annotation, = integer of 32 bits with a value of 5
|
||||
println!("{} {} {}", logical, a_float, rare_integer);
|
||||
|
||||
// All are inmutable by default
|
||||
// mut keyword
|
||||
let mut mutable_int = 12i32;
|
||||
println!("int: {}", mutable_int);
|
||||
mutable_int = 21;
|
||||
println!("int mutated: {}", mutable_int);
|
||||
|
||||
let mutable_int = true; // variables can be overwritten with shadowing
|
||||
println!("not an int anymore {}", mutable_int);
|
||||
|
||||
let thousand = 1_000;
|
||||
println!(
|
||||
"1_000 is a good way to express {} in order to make it readable",
|
||||
thousand
|
||||
);
|
||||
|
||||
let cientific = 7.6e-4;
|
||||
println!(
|
||||
"Cientific notation is also valid, as 7.6e-4 would be stored as {}",
|
||||
cientific
|
||||
);
|
||||
|
||||
println!(
|
||||
"Remember that the type can be specified with the number, as 1u32 is {}",
|
||||
1u32
|
||||
);
|
||||
|
||||
let my_tuple = (1, "corcho", true);
|
||||
|
||||
println!(
|
||||
"The second value of the tuple {:?} is {}",
|
||||
my_tuple, my_tuple.1
|
||||
);
|
||||
|
||||
let another_tuple = (1i32, false);
|
||||
println!(
|
||||
"A function can also receive and return tuples, such as reverse return {:?} on {:?}",
|
||||
reverse_tuple(another_tuple),
|
||||
another_tuple
|
||||
);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EmulatedMatrix(f32, f32, f32, f32);
|
||||
|
||||
let matrix = EmulatedMatrix(1.1, 1.4, 0.5, 7.3);
|
||||
println!("Simulated: {:?}", matrix);
|
||||
let EmulatedMatrix(a, b, c, d) = matrix;
|
||||
println!("Data can also be destructured: {}, {}, {}, {}", a, b, c, d);
|
||||
|
||||
// EXERCISE 1: fmt::Display Matrix (make it easy, you dont know loops yet)
|
||||
println!("EXERCISE 1: Print a matrix with the tuple struct:");
|
||||
use std::fmt::{Display, Formatter, Result};
|
||||
|
||||
impl Display for EmulatedMatrix {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
write!(f, "({}, {})\n({} {})", &self.0, &self.1, &self.2, &self.3)
|
||||
}
|
||||
}
|
||||
|
||||
println!("{}", matrix);
|
||||
|
||||
// EXERCISE 2: transpose a EmulatedMatrix (make it easy, you dont know loops yet)
|
||||
println!("EXERCISE 2: make a simple transpose function (later on we'll improve it with loops)");
|
||||
fn transpose(m: EmulatedMatrix) -> EmulatedMatrix {
|
||||
let EmulatedMatrix(a, b, c, d) = m;
|
||||
return EmulatedMatrix(a, c, b, d);
|
||||
}
|
||||
|
||||
println!("{}", transpose(matrix));
|
||||
|
||||
// Arrays
|
||||
let mut onetofive: [i8; 5] = [1, 2, 3, 4, 5];
|
||||
println!("The fourth element is {}", onetofive[3]);
|
||||
let allthrees: [i32; 10] = [3; 10];
|
||||
println!(
|
||||
"All threes: {:?} have a size of {}",
|
||||
allthrees,
|
||||
allthrees.len()
|
||||
);
|
||||
|
||||
use std::mem;
|
||||
println!("All threes accupies {} bytes", mem::size_of_val(&allthrees));
|
||||
|
||||
// Sclice: pointer to a portion of an array
|
||||
// '&' means borrowing
|
||||
let onetothree = &mut onetofive[1..3];
|
||||
println!("One to three slice {:?}", onetothree);
|
||||
onetothree[1] = 7;
|
||||
println!("onetofive slice {:?} after mutating onetothree", onetofive);
|
||||
|
||||
for i in 0..onetofive.len() + 1 {
|
||||
// force a failure
|
||||
match onetofive.get(i) {
|
||||
Some(xval) => println!("{}: {}", i, xval),
|
||||
None => println!("Slow down! {} is too far!", i),
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/types.rs
Normal file
20
src/types.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
pub fn types_module() {
|
||||
// casting with as: types can be casted as long as the types overlap.
|
||||
let decimal = 65.4321;
|
||||
let integer: u8 = decimal as u8;
|
||||
|
||||
println!("The decimal {} is casted to the u8 {}", decimal, integer);
|
||||
|
||||
// dangerous carting can be done with some methods
|
||||
unsafe {
|
||||
println!(
|
||||
"f32 -100.0 as u8 is : {}",
|
||||
(-100.0_f32).to_int_unchecked::<u8>()
|
||||
);
|
||||
}
|
||||
|
||||
// type alias are also a thing
|
||||
type Inch = u64;
|
||||
let inch: Inch = 5;
|
||||
println!("using type aliases {}", inch);
|
||||
}
|
||||
27
src/variablebindings.rs
Normal file
27
src/variablebindings.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
pub fn variable_bindings_module() {
|
||||
// mutability: variables are immutable by default
|
||||
// we can say they are Frozen by default
|
||||
let mut mutable_number = 1;
|
||||
|
||||
mutable_number += 1;
|
||||
println!("number mutated: {}", mutable_number);
|
||||
|
||||
// scope: variables have block scope, and can be shadowed
|
||||
let shadowed_variable = 1;
|
||||
|
||||
{
|
||||
let shadowed_variable = 2;
|
||||
println!("shadowed inside block: {}", shadowed_variable);
|
||||
}
|
||||
println!("shadowed outside block: {}", shadowed_variable);
|
||||
|
||||
// declare first approach: you can declare first and initialize later, but its not recommended.
|
||||
let my_binding;
|
||||
|
||||
my_binding = 2;
|
||||
|
||||
println!(
|
||||
"A variable can be initialized later even if the declaration has no type: {}",
|
||||
my_binding
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user