// hello.rs
fn main() {
    println!("Hello, world!");
}
          
          
rustc hello.rs
          
          // things_we_know.rs
fn main(){
  let x = 37; /i32
  let y = 2.3; // f64
  let y: f32 = 1.4; //f32
  let z: [i32;3] = [1, 2, 3];
  let a = [3; 5]; // [3,3,3,3,3]
  // if expressions
  let _ = if x == 37 {
    println!("{} is a number",x)
  }else{
    println!("I am not 37")
  };
  // pattern matching
  let (a,b,c) = ("I'm ",1,'8');
  match x {
    1 => 'a',
    2|3 => 'b',
    4..=36 => 'c' //range inclusive
    37 => 'd',
    _ => 'e',
  };
  let a = 37;
  println!("{}",a);
  {
    let a = a + 2; 
    println!("{}",a);
  }
  println!("{}",a);
  other();
  other2(3);
  other3(5);
}
fn other(){
  println!("unit -> unit");
}
fn other2(x: u32){
  println!("u32 ({}) -> unit",x);
}
fn other3(x: u32)->u32{
  let res = x + 1;
  println!("u32 ({}) -> u32({})",x,res);
  res
}
          
          rust prefers static and explicit typing
// new_things.rs
let x = 4;
x = 5;         // Error - not mutable
let mut x = 4; // fix
x = 5;        
let a = {       // codeblocks
  let x = 5;
  let y = 10;
  let mut z = x + y;
  z = z - 4;
  z
}
loop{         //loop
  println!("and on...")
};
let a = loop{ //break with return value
  break 5;
};
'named_loop': loop{ //named loops for better control flow
  'other_loop': loop{
    break 'named_loop;
  }
}
while x > 0{ //while 
  x = x - 1;
}
for y in 0..10{ //for x in range(10)
  println!("{}",y);
}
for s in [1,2,3]{ //for as expected
  println!("{}",s);
}
          
          
          Consider the following
/* C */
char* str = "hello";
int x = str;
float y = char[9];
          
          Type un-safe
/* C */
char* s = malloc();
free(s);
printf("%d",s[2]);
          
          Temporally un-safe
A compiler can catch type errors,can it catch memory errors?
Solution: manage memory better
most languages you have seen have garbage collector
Rust: no GC and allows for mutability
Rust: no GC and allows for mutability
/* mut.rs */
let mut x = 5;
x += 3;
println!("{}",x);
while x > 0 {
  x -= 1;
  println!("{}",x);
}
let mut arr = [1,2,3];
arr[0] = 4;
          
          
/* ownership.rs */
let s1 = String::from("hello");
let s2 = s1;
println!("{}",s1);
          
          
/* drop.rs */
{
  let s1 = String::from("hello");
}
let s2 = s1;
          
          
fn main() {
    let s = String::from("hello");  
    takes_ownership(s);             
    let x = 5;                      
    makes_copy(x);                  
} 
fn takes_ownership(some_string: String) { 
    println!("{}", some_string);
} 
fn makes_copy(some_integer: i32) { 
    println!("{}", some_integer);
}
          
          
fn main() {
    let s1 = gives_ownership();         
    let s2 = String::from("hello");     
    let s3 = takes_and_gives_back(s2);  
} 
fn gives_ownership() -> String {             
    let some_string = String::from("yours"); 
    some_string                              
}
fn takes_and_gives_back(a_string: String) -> String { 
    a_string  
}
          
          Ownerships can cause issues
Can borrow by making a non-owning pointer
fn main() {
    let mut s = String::from("hello");
    change(&mut s);
}
fn change(some_string: &mut String) {
    some_string.push_str(", world");
}
          
          Ownerships can cause issues
Can borrow by making a non-owning pointer
fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);
    println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
    s.len()
}
          
          Ownerships can cause issues
Can borrow by making a non-owning pointer
fn main() {
    let mut s = String::from("hello");
    {
        let r1 = &mut s;
    } 
    let r2 = &mut s;
}
          
          Slices are special types of references
Strings, vectors and arrays use slices
pub fn first_word (s: &String) -> &str {
  for (i, item) in s.char_indices() {
    if item == ' ' {
      return &s[0..i];
    }
  }
  s.as_str()  
}