Last active
November 7, 2020 11:34
-
-
Save mokua/50c97ebbb0dbecd5da780e55a6764879 to your computer and use it in GitHub Desktop.
rust 101
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Variables and Mutability | |
------------- | |
let x = 9; // immutable variable | |
//x = 10 // error can assign to a mutable variable | |
let mut y = 19; //mutable variable | |
y = 20; //we can assign another value | |
//constants | |
const MAX_POINTS:u32 = 100_000; // constant | |
//shadowing | |
let p = 7; | |
let p = p +3; | |
let p = p + 1; | |
let spaces = " "; | |
let spaces = spaces.len(); // you can change type when shadowing ; ooh, why?? | |
Data types | |
----------- | |
+ scalar types | |
+ Integer types | |
Length Signed Unsigned | |
8-bit i8 u8 | |
16-bit i16 u16 | |
32-bit i32 u32 | |
64-bit i64 u64 | |
128-bit i128 u128 | |
arch isize usize | |
+ floating point types | |
f32 and f64 | |
+ boolean types | |
let f : bool = false; | |
+ character type | |
let z = 'z'; | |
let p = 'p'; | |
+ Compound Types | |
+ Tuple | |
let tup: (i32,f64) = (32,3.467); | |
//accessing the elemts | |
let (x,y) = tup; //destructure using pattern matching | |
let first = tup.x; | |
let second = tup.y; | |
+ Array | |
let a = [2,3,4,5,6,7]; //allocated on the stack, fixed sized, one type | |
let a:[i32;5] = [4,5,6,7,9]; // let a:[<elemet type>; no of elemets] | |
let a = [3;5]; // an arrray of size 5 with all elemnets being 3 | |
let init = a[0]; | |
functions | |
---------- | |
fn print_hello(){ | |
println!("hello world"); | |
} | |
//fuction parameters | |
fn print_it(x: i32, y:f64){ | |
println!("the value x is {} and y is {} ", x, y); | |
} | |
//Statements are instructions that perform some action and do not return a value. examples: | |
- let p = 13; | |
- function defination | |
//Expressions evaluate to a resulting value. Expressions do not include ending semicolons | |
- 5+6, | |
- 10 | |
- blocks | |
{ | |
x+1 | |
} | |
//function return values | |
fn pi() -> f64{ | |
3.142 | |
} | |
fn area(radius: f64) -> f64{ | |
pi() * radius * radius | |
} | |
control flow | |
------------ | |
//if expressions | |
let x = 9; | |
f x < 10{ | |
println!("the value is less than 10"); | |
}else{ | |
println!("the value is greater than 10"); | |
} | |
//else if | |
let number = 18; | |
if number %4 ==0 { | |
println!("divisble by 4"); | |
}else if number %6 == 0{ | |
println!("divisble by 6"); | |
}else { | |
println!("not divisble by 4 or 6 "); | |
} | |
//let if | |
let conidtion = true; | |
let number = if conidtion { 7 } else { 10}; | |
//repetition with loops | |
//a) loop | |
//repeat with loop | |
loop{ | |
println!("print again"); | |
} | |
//return values from loops | |
let mut counter = 1; | |
let result = loop{ | |
counter += 1; | |
if counter == 10 { | |
break counter * 2; | |
} | |
}; | |
//b) while | |
let number = 8; | |
while number != 0{ | |
println!(" {} ", number); | |
number -=1; | |
} | |
//c) for | |
let a = [1,2,3,4,5,6]; | |
for elemet in a.iter(){ | |
println!("element : {}", element); | |
} | |
for number in (1..5).rev(){ | |
println!("{}", number); | |
} | |
Ownership | |
---------- | |
//memory is managed through a system of ownership with a set of rules that the compiler checks at compile time | |
//ownership rules | |
/* | |
Each value in Rust has a variable that’s called its owner. | |
There can only be one owner at a time. | |
When the owner goes out of scope, the value will be dropped. | |
*/ | |
//variable scope | |
{ //s not valid | |
let s = "hello"; //s valid from here | |
//s is available here | |
} //s is not valid here | |
//memory allocation and dealloaction | |
{ | |
let s = String::from("Hellow World"); //allocates memory on the heap | |
//s can be used here | |
} //rust calls drop and deallocaets the memmort | |
//move | |
{ | |
let s1 = String::from("Hello World"); | |
let s2 = s1; //Rust moves the pointer s1 to s2 (like a shallow copy of the pointer on the stack and invalidates the pointer s1) | |
println!("the vlaue of s1 is {}", s1 ) ; //this will cause an error | |
} //rust drops the s2 and deallocates the memory | |
//clone | |
{ | |
let s1 = String::from("Hello World"); //allocates memory on the heap for the string and returns a pointer on the stack to that data on the heap | |
let s2 = s1.clone(); //deep copy the stack and heap data | |
println!("the s1 {} and s2 {}", s1, s2); //this works | |
} //deallocates both s1 and s2 | |
//stack data copy | |
{ | |
let x = 6; //all types marked with the trait Copy e.g. integer,float,char,bool, -- put on the stack | |
let y = x; //this is a copy since its on the stack | |
println!("the x {} and y {} ", x,y); //works | |
} //dropped | |
//ownership and functions | |
fn main(){ | |
let hello = String::from("Hello world"); //allocates the hello on the heap | |
println!("The hello {} ", hello); //can use it here | |
take_ownership(hello); //move - transfer ownership -- to take_ownership | |
println!("try it again {} ", hello); //error -- use after move | |
} | |
fn take_ownership(s: String) { //takes ownership | |
println!("tkane : {}", s); //use it | |
} //drop s and deallocate the memmory, this is no longer accessible | |
//return values and scopes | |
fn main(){ | |
let s1 = make_string(); //the make_string makes it and moves the value to main | |
println!("the s {}", s1); //can use it | |
let s2 = String::from("Hello world"); //create & allocate s2 | |
let s3 = use_and_return(s2); //move ownership to fn use and return | |
println!("use {}", s3) //we can use s3 here since it has been moved back to main | |
} //deallocates s1 , s2 and s3 | |
fn make_string() -> String{ | |
let ss = String::from("Made and retuend") //allocates on the heap and returns it | |
ss //moves ss to main | |
} | |
fn use_and_return(input : String) -> String{ //takes owneship of input | |
println!("using and munching {}" , input); //can use it | |
input //and moves it back | |
} | |
References & borrowing | |
---------- | |
fn main(){ | |
let s1 = String::from("Hello Worlsd"); | |
let len = calculate_length(&s1); //&s1 -- reference to s1 ,a pointer to s1 on the stack , but does not own it ==> borrowing | |
println!("s1 {} has length {} ", s1, len); | |
} | |
fn calculate_length(s: &String) -> u32{ //&String -- expects a reference to String | |
s.len(); | |
} //s goes out of scope but does not deallocate the heap data for s since it does not have ownership ==> returning the borrowed | |
//mutable reference : &mut String | |
fn main(){ | |
let s1 = String::from("hello world") | |
change(&mut s1); | |
println!("changed {} ", s1); | |
dwiddle(&mut s1, &mut s1 ); //this fails, rust prohibits having more than one mutable reference in the same scope ; prevents data races | |
} | |
fn change(s: &mut String) { | |
s.push_str("...ding dong"); | |
} | |
//multiple mutable refs in the same scope | |
fn dwiddle(s1: &mut String, s2: &mut String){ | |
//edit them | |
} | |
//mixing mutable and immutable refs in the samce scope | |
{ | |
let mut s = String::from("Hellow"); | |
let r1 = &s; | |
let r2 = &s; | |
let r3 = &mut s ; //problems , this is bcoz the mutable refernce means s can change and r1 & r2 will be left holding invalid pointers | |
println!("them refs {} {} and {}", r1,r2,r3); //note that since r1 & r2 are still in scope, r3 will fail | |
println!("them r3 {} ", r3); //but this will work since r1 & r2 and out of scope | |
} | |
//dangling reference | |
fn main(){ | |
let nothing = dangle(); | |
} | |
fn dangle() -> &String{ //returns a ref to a strig | |
let f = String::from("hellow"); //f is allocated here | |
&f //this is pointing to f, for now ... | |
} //f is deallocated and thus leaving f pointing into freed memory --- dangling pointer!! | |
slice type | |
----------- | |
//string slice , &str | |
let s = String::from("Hello World"); | |
let p = "Hello world"; // type : &str | |
let h = &s[0..4]; // get a slice, ref to the underlaying heap data from 0..4, same as &s[..4]; | |
let w = &s[6..10]; // get a slice, ref to the underlying heap data from 6..10, same as &s[6..]; | |
let a = [1,2,3,4,5]; | |
let a1 = &a[..3]; // [1,2,3], type : &[i32] | |
structs | |
------ | |
//define | |
struct User{ | |
username: String, | |
email:String, | |
active: bool, | |
signed_in_count:u32, | |
} | |
//instantiate | |
let mut u = User{ | |
username: String::from("the_ghc"), | |
email:String::from("dd@gmail.com"), | |
active:false, | |
signed_in_count: 200, | |
}; | |
u.email = String::from("test@ff.com"); // to access the fields, use . operator | |
fn build_user(username: String) -> User{ | |
User{ | |
username: username, | |
email:String::from("dd@gmail.com"), | |
active:false, | |
signed_in_count: 200, | |
} | |
} | |
//init short hand when vriables and fields have the same name | |
fn build_user(username: String) -> User{ | |
User{ | |
username, //init short hand | |
email:String::from("dd@gmail.com"), | |
active:false, | |
signed_in_count: 200, | |
} | |
} | |
//struct update syntax | |
let user1 = build_user("jack"); | |
let user2 = User{ | |
username:String::from("pterh"); | |
..user1 //the rest of the attributes we take the same from user1 | |
}; | |
//tuple structs | |
struct Color(i32,i32,i32);// give the whole tuple a name and make the tuple be a different type from other tuples, | |
//unit stuct | |
struct Holder{} | |
Method syntax | |
-------------- | |
const pi:f64 = 3.142 | |
#[derive(Debug)] | |
struct Circle{ | |
radius: f64, | |
} | |
impl Circle{ // method defined inside the context of a struct | |
fn area(&self) -> f64{ // the first parameter is always self (receiver) -> the instance of the struct on which the method is being invoked | |
self.radius * self.radius * pi | |
} | |
} | |
fn main(){ | |
let c = Circle{ | |
radius: 11.22 | |
}; | |
let a = c.area(); //invocation using the dot (.) sytanx ; note that rust does automatic referencing and dereferencing, | |
println!("the ares {} ", a); | |
} | |
//methods with more paramaters | |
impl Circle{ | |
fn area(&self, pi: f64) -> f64{ | |
self.radius * self.radius * pi | |
} | |
} | |
//associated functions | |
impl Circle{ //associated with a struct but does not take reciver | |
fn make_it(radius: f64) -> Circle{ | |
Circle{ | |
radius | |
} | |
} | |
} | |
let c = Circle::make_it(11.2); // sytanx :: | |
enum | |
----- | |
//defining an enum | |
enum Day{ | |
Monday, Tueday, Wednesday, Thurday, Friday, Saturday,Sunday, | |
} | |
let mon = Day::Monday; | |
println!("{} ", mon.readable_string()); | |
impl Day{ | |
fn readable_string(&self) -> String{ // can define functions in the impl block for an enum similar to a struct | |
match *self{ //pattern match on the enum value | |
Day::Monday => format!("Today is Monday"), | |
_ => format!("The rest"), | |
} | |
} | |
} | |
//enums can encode values inside them | |
#[derive(Debug)] | |
struct Dimensions{ | |
mass: f64, | |
radius: f64 | |
}; | |
#[derive(Debug)] | |
enum Planet{ | |
MERCURY (Dimensions) , //mass, radius | |
VENUS (Dimensions), | |
EARTH (Dimensions), | |
MARS (Dimensions), | |
JUPITER (Dimensions), | |
SATURN (Dimensions), | |
URANUS (Dimensions), | |
NEPTUNE (Dimensions), | |
}; | |
const G:f64 = 6.67300E-11; | |
use Planet::*; //bring the planets into scope | |
impl Planet{ | |
fn make_mercury() -> Planet{ | |
let t = MERCURY(Dimensions{ mass: 5.976e+24, radius: 6.37814e6}); | |
t | |
} | |
fn surface_gravity(&self) -> f64{ | |
match self{ | |
MERCURY(Dimensions{mass, radius}) => G * mass / (radius * radius), | |
_ => 0.0 | |
} | |
} | |
fn surface_weight(&self, other_mass: f64) -> f64{ | |
match self{ | |
MERCURY(_) => other_mass * self.surface_gravity(), | |
_ => 0.0 | |
} | |
} | |
} | |
let m = Planet::make_mercury(); | |
println!("Mercury surface gravity : {}, surface weight {} ", m.surface_gravity(), m.surface_weight(80.00)); | |
option ** | |
------ | |
enum Option<T>{ | |
Some(T), | |
None, | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment