CMSC330

Rust

Rust

Intro
Syntax
Ownerships
References

Intro

Intro

Our First Program

// hello.rs
fn main() {
    println!("Hello, world!");
}
          
  • Comments use //
  • Need a main function

rustc hello.rs
          

Syntax

Our Second Program
// things_we_know.rs
fn main(){
  let x = 37;

  let _ = if x == 37 {
    println!("{} is a number",x); 
  }else{
    println!("I am not 37");
  };

  for y in 0..10{
    println!("{}",y);
  }
  let (a,b,c) = ("I'm ",1,'8');
  
  for x in [1,2,3].iter(){
    println!("{}",s);
  }
}
          

rust prefers static and explicit typing

Ownership

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

Solution: manage memory better

Solution: manage memory better

most languages you have seen have garbage collector

  • GC is costly
  • Space and runtime tradeoffs
  • Immutability helps optimize GC

Rust: no GC and allows for mutability

Rust: no GC and allows for immutability

  • Each value in Rust has an owner
  • There can only be one owner at a time
  • When the owner goes out of scope, the value will be dropped
  • Each value in Rust has an owner
  • There can only be one owner at a time
  • When the owner goes out of scope, the value will be dropped

/* 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;
          
  • Each value in Rust has an owner
  • There can only be one owner at a time
  • When the owner goes out of scope, the value will be dropped

/* ownership.rs */
let s1 = String::from("hello");
let s2 = s1;
println!("{}",s1);
          
  • Each value in Rust has an owner
  • There can only be one owner at a time
  • When the owner goes out of scope, the value will be dropped

/* 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  
}
          

References

Ownerships can cause issues

Can borrow by making a non-owning pointer

  • One Mutable reference
  • infinitely many immutable references

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

  • One Mutable reference
  • infinitely many immutable references

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

  • One Mutable reference
  • infinitely many immutable references

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

  • Point to a place in memory
  • Have a length

pub fn first_word (s: &String) -> &str {
  for (i, item) in s.char_indices() {
    if item == ' ' {
      return &s[0..i];
    }
  }
  s.as_str()  
}