Skip to content

Instantly share code, notes, and snippets.

@mokua
Last active November 7, 2020 11:34
Show Gist options
  • Save mokua/50c97ebbb0dbecd5da780e55a6764879 to your computer and use it in GitHub Desktop.
Save mokua/50c97ebbb0dbecd5da780e55a6764879 to your computer and use it in GitHub Desktop.
rust 101
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