🌱
Dev Compendium
  • Ethereum
    • Solidity
      • EVM
      • Architecture
      • Execution Context
      • Transactions
      • Gas
      • Calldata, Memory & Storage
      • Gas Optimisation
      • Function Declarations
      • receive() & fallback()
      • CALL vs. DELEGATE CALL
    • Yul
      • Introduction
      • Types
      • Basic Operations
      • Storage
      • Memory
        • Arrays
        • Structs
        • Tuples, revert, keccak256
        • Logs and Events
        • Gotchas
        • abi.encode
      • Calldata
        • External Calls
        • Dynamic Length Inputs
        • Transferring Value
        • Receiving Contract Calls
      • Contracts in Yul
      • Other Yul Functions
    • Foundry
    • Security
      • Common Vulnerabilities
      • Best Practices
      • Development Workflow
      • Contract Migration
    • Auditing Tools
      • Slither
      • Mythril
      • Fuzzing
    • Upgradable Contracts
      • Upgrade Patterns
      • ERC-1967 Implementation
      • Deployment
    • MEV
    • Tooling
      • Chainlink
      • IPFS
      • Radicle
    • Frontend
      • Contract Hooks
      • Wallet Connection
        • wagmi.sh
        • Rainbow Kit
      • thirdweb
    • Protocol Research
      • Uniswap v2
      • Uniswap v3
      • Curve
      • GMX
  • Starkware
    • Fundamentals
    • Account Abstraction
    • Universal Deployer
    • Cairo 1.0
    • starknet.js
    • Security Model
  • Zero Knowledge
    • Group Theory
    • ECDSA
  • Rust
    • Basic Operations
    • Set up
    • Primitives
    • Control Flow
    • Mutability & Shadowing
    • Adding Behavior
    • Lifetimes
    • Std Library
  • SUI
    • Architecture
    • Consensus Mechanism
    • Local Node Setup
    • Sui Client CLI
    • Move Contracts
      • Move
      • Move.toml
      • Move.lock
      • Accessing Time in Sui Move
      • Set up Development Framework
      • Debug & Publish
      • Package Upgrades
      • Sui Move Library
      • Difference from Core Move
    • Object Programming
      • Object Basics
      • Using Objects
      • Immutable Objects
      • Object Wrapping
      • Dynamic Fields
      • Collections
      • Unit Testing
      • Deployment with CLI
  • NEAR
    • Architecture
    • Contract Standards
      • Fungible Token (NEP-141)
      • Non-Fungible Token (NEP-171)
      • Storage Management (NEP-145)
      • Events (NEP-297)
      • Meta-Transactions
    • Rust Contracts
      • Development Workflow
      • Smart Contract Layout
      • Storage Management
      • Events & Meta-transactions
      • Method Types
      • Upgrading Contracts
      • Unit Testing
    • NEAR Libraries
    • Environment Variables
    • Serialisation
    • Security Concepts
    • Collections
    • JS SDK
Powered by GitBook
On this page
  1. Rust

Basic Operations

introduction

  • difference between macros and functions: macros have the ! symbol

  • they behave similarly

  • a macro can take an arbitrary number of arguments, cant do that if it were a regular function

fn main() {
    println!("Hello, world!");
}
  • if statements dont need to have parentheses

fn main() {
  let x = 42; 

  if x == 42 {
    println!("x is 42"); 
  } else if  x % 2 == 0 {
    println!("x is even"); 
  } else {
    println!("x is odd"); 
  }
}
  • if statements can have return values

fn main() {
  let x = 42; 
  let msg = if x == 42 {
    "x is 42"
  } else if x % 2 == 0 {
    "even"
  } else {
    "odd"
  }; 

  println!("{}", msg); 
}
  • rust makes a distinction between string literals and string types

  • println statement only accepts string literals

  • for loops:

fn main() {
    for i in 0..10 {
        println!("{}", i);
    }
}
  • fizzbuzz

fn main() {
    for i in 0..20 {
        if i % 3 == 0 && i % 5 == 0 {
            println!("Fizzbuzz");
        } else if i % 3 == 0 {
             println!("Fizz");
        } else if i % 5 == 0 {
             println!("buzz");
        } else {
             println!("{}", i);
        }
    }
}
  • integers and floats

  • default integer type is the signed i32, can use bigger types like i64 or i128 , or unsigned u128 if we dont need negative values

  • two types of floats, f32 and f64

  • all integer sizes supported by rust: 8 16 32 64 128

fn integer() -> i32 {
    return 42;
}

fn float() -> f64 {
    return 3.142; 
}

fn main() {
    let int = integer(); 
    let flt = float();
    println!("{}", int);
    println!("{}", flt); 
}
  • overflows and underflows

// panic, due to underflow, returns 10 if i8 is used 
fn main() {
    let mut x: u8 = 10;
    x = x - 20;
    println!("{}", x); 
}
  • we can return values without using the return keyword, if the last value in the function does not end with a semicolon

// idiomatic rust 
fn mul(x: i32, y:i32) -> i32 {
    x * y
}

// "traditional" representation 
fn mul(x: i32, y:i32) -> i32 {
    return x * y; 
}
  • if we want to do an early return, we would have to use the return statement

fn factorial(n: u128) -> u128 {
    if n == 0 || n == 1 {
        return 1;
    }
    n * factorial(n-1) 
}
  • this still compiles because the final return value originates from the if statement

    • will not work if we add semicolons to after the x and y values

fn min(x: i32, y: i32) -> i32 {
    if x < y { x } else { y }
}
  • vectors are like lists/arrays in other languages

  • have to use a different format string if we want to print a vector

fn main() {
    let mut x: Vec<i32> = Vec::new();
    x.push(5);
    x.push(10);

    println!("{:?}", x);
}
  • loop through vector length and print elements

fn main() {
    let mut x: Vec<i32> = Vec::new();
    x.push(5);
    x.push(10);

    for i in 0..x.len() {
        println!("{}", x[i]);
    }
} 
  • popping value from Vector may return Option<i32>

  • options are an important part of why is rust is safer than other languages, because when you pop an item out of an array, there is no guarantee what type it is

  • generally rust returns options when there’s a possibility that an operation might fail

  • forces user to deal with an invalid value at compile time

fn main() {
    let mut v: Vec<i32> = [1, 2, 3].to_vec();

    let last = v.pop();
    println!("{:?}", last); // prints Some(3) 
}
  • an option can be one of two types: some and none

    • none - returns when we would usually expect null pointers or exceptions

    • some - returns when succeeds

  • cannot treat options like the value they contain, e.g. cannot add an integer to an option

// will return Option as someone might try to convert a value that is invalid
fn main() {
    let my_char = '3'.to_digit(10);
    println!("{:?}", my_char); // returns Some(3) 
}
  • rust does not always produce an option, will panic in some other situations, for example when accessing an array out of bounds

// this code panics 
fn main() {
    let my_vec = Vec::from([1, 2, 4]);
    println!("{:?}", my_vec[10]);
}
  • can convert to another form to return an option instead

fn main() {
    let my_vec = Vec::from([1, 2, 4]);
    println!("{:?}", my_vec.get(10)); // returns None 

		let x: i32 = 1;
    println!("{:?}", x.checked_div(10)); // returns Some(0) 
}
  • convert Some(3) into a regular 3

PreviousECDSANextSet up

Last updated 1 year ago