Getting started

If, loops & match

if/else and loops carry over directly. Rust adds match (a superpowered switch) and makes if an expression that returns a value.

Control flow is familiar territory. if / else and loops read almost the same; the new tools are match (pattern-matching switch) and the fact that if and match are expressions — they return a value.

Classify a number
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Flow {
    function classify(uint32 n) external pure returns (string memory) {
        if (n == 0) {
            return "zero";
        }

        uint32 sum = 0;
        for (uint32 i = 1; i <= n; i++) {
            sum += i;
        }

        if (sum % 2 == 0) {
            return "even";
        } else {
            return "odd";
        }
    }
}
Rust
use near_sdk::near;

#[near(contract_state)]
#[derive(Default)]
pub struct Flow {}

#[near]
impl Flow {
    pub fn classify(&self, n: u32) -> String {
        if n == 0 {
            return "zero".to_string();
        }

        let mut sum = 0u32;
        for i in 1..=n {
            sum += i;
        }

        // match is a switch that returns a value
        match sum % 2 {
            0 => "even".to_string(),
            _ => "odd".to_string(),
        }
    }
}
Coming from EVM

for (uint i; i < n; i++) ↔ for i in 0..n (or 1..=n for inclusive). while is the same. There is no continue-less C-style header — you iterate over ranges and collections.

match is switch with exhaustiveness: the compiler makes you handle every case (_ is the default). Because it is an expression, the whole match evaluates to the value you return.

A function’s last expression (no semicolon) is its return value, so many methods end with a match or a value instead of an explicit return.