| Term | What it is | When it's used |
|---|---|---|
| let | Creates a new variable | Every time you store a value |
| mut | Allows a variable to change after it is set | When your program needs to update state |
| Immutable | Cannot change after being set | Default Rust variable behavior |
| Variable | A named value | let age = 25; |
| Unit type () | Rust's empty value — means "nothing" | When a function returns nothing meaningful |
| Integer | A whole number | Counts, balances, indexes |
| Signed integer i | Integer that can be negative (i8, i32, i64) | Temperatures, gains/losses |
| Unsigned integer u | Integer that cannot be negative (u8, u32, u64) | Balances, counts, addresses |
| u64 | Unsigned 64-bit integer — whole number, no negatives | Payment amounts, token balances, timestamps |
| u8 | Unsigned 8-bit integer — 0 to 255 | Bytes, wallet address components |
| Floating point f | A decimal number (f32, f64) | Measurements — rarely used in Solana |
| f64 | A 64-bit decimal number | Avoid in Solana — use integer lamports instead |
| bool | true or false — nothing else | Status flags: is_paid, is_verified |
| char | One character — single quotes | 'A', '🔥' — single symbols, not strings |
| &str | A piece of text — borrowed string slice | Labels, names, error messages |
| String | Owned, growable text | Text you build or change at runtime |
| Tuple | A group of mixed-type values — fixed size | ("Alice", 25, true) |
| Array | A fixed list where every item is the same type | [1, 2, 3] |
| Slice | A borrowed window into part of an array | &scores[1..4] — start included, end excluded |
| as | Converts one type to another | When you need two different types to work together |
| println! | Prints a line to the terminal | Debugging or showing output |
| {:?} | Debug print formatting | Printing arrays and tuples that {} cannot print |
| [u8; 32] | An array of exactly 32 unsigned bytes | Wallet addresses on Solana |
| Shadowing | Reusing a variable name with a new let binding — the old value is replaced | Transforming a value while keeping the same name |
| _ | Prefix for variables the compiler should not warn about as unused; also ignores a value in patterns | let _unused = 5; or skipping a tuple element |
| Destructuring | Unpacking a tuple or struct into individual named variables in one line | let (plan, fee) = (1_000_000u64, 50_000u64); |
| const | A value that never changes — must have an explicit type; cannot be computed at runtime | const MAX_FEE: u64 = 50_000; — storing fixed limits |
| Term | What it is | When it's used |
|---|---|---|
| fn | The keyword that starts a function definition | Every function you write |
| Function | A named block of code with typed inputs and optional output | Any time you want reusable logic |
| Parameter | A typed input slot in the function signature: name: &str | When declaring what a function accepts |
| Argument | The actual value passed when calling | When you call a function |
| -> | Arrow separating parameters from the return type | When a function gives a value back |
| Return type | The type of value a function sends back | Declared after -> — if you declare it, you must return it |
| return | Sends a value back to the caller and exits the function | At the end of a function that gives something back |
| format! | Macro that builds a new String from a template | When you need text as a value, not printed |
| #[allow(dead_code)] | Suppresses the "function never used" compiler warning | During development before all functions are wired up |
| Attribute | A tag above an item that changes how the compiler processes it | #[allow(dead_code)], #[derive(...)] |
| Implicit return | The last expression in a function body without a semicolon is automatically returned | fn add(x: i32, y: i32) -> i32 { x + y } |
| Scope | The block of code where a variable is valid — from its declaration to the closing } | A variable declared inside { } cannot be used outside that block |
| Diverging function | A function that never returns to the caller — its return type is ! | When a function always panics, loops forever, or exits |
| ! (never type) | The return type of a function that never returns | fn never_return() -> ! { panic!() } |
| unimplemented! | A macro that panics with "not yet implemented" — used as a placeholder | When writing function structure before filling in the logic |
| todo! | A macro that panics with "not yet implemented" | Placeholder for code you plan to write later |
| Term | What it is | When it's used |
|---|---|---|
| Owner | The variable responsible for a value — when it goes out of scope, the value is freed | Always — every value has exactly one |
| Move | Transferring ownership to a new variable — the original can no longer be used | When passing a String or Vec to a function |
| Copy | Duplicating a value so both the original and the new variable stay valid | Integers, booleans, floats — they copy automatically |
| Clone | An explicit full copy of a heap-allocated value | s1.clone() — use when you need two separate values |
| Drop | When a value goes out of scope and its memory is freed | Happens automatically at the } that closes the scope |
| Stack | Fast memory for values with a known, fixed size | i32, bool, char — automatically freed when a function ends |
| Heap | Flexible memory for values that grow or have unknown size | String, Vec — requires ownership tracking to know when to free |
| Ownership rules | Rust's three rules: one owner, one owner at a time, dropped when owner goes out of scope | The foundation of how Rust manages memory without a garbage collector |
| Ownership into function | Passing a String to a function moves ownership — the caller's variable is no longer valid | When a helper takes a value and the caller still needs it afterward |
| Return ownership | A function can give ownership back by returning the value | The only way to use a value in main after passing it to a function that takes ownership |
| as_bytes() | Borrows a String as a byte slice — the original string stays valid | When you need to inspect bytes without consuming the string |
| into_bytes() | Consumes a String and converts it to a Vec<u8> — the original is gone afterward | When you need the raw bytes and will no longer use the string |
| Box<T> | Allocates a value on the heap and gives you a pointer to it | When you need to heap-allocate a type that would normally go on the stack |
| Mutability on transfer | When ownership moves, the new variable sets its own mutability | let mut s1 = s; — s1 can be mutated even if s was immutable |
| Term | What it is | When it's used |
|---|---|---|
| Borrow &T | A read-only reference — use a value without taking ownership | When a function only needs to read a value |
| Mutable borrow &mut T | A read-write reference — use and change a value | When a function needs to modify a value |
| Scope | The block a variable lives in — between { and } | Determines when a value is dropped |
| Lifetime | How long a reference stays valid — compiler tracks this automatically | You read lifetimes in Anchor ('info); rarely write them yourself |
| Borrowing rules | Either one mutable reference OR any number of immutable ones — never both at the same time; references must always be valid | How Rust prevents data races and dangling pointers at compile time |
| Dangling reference | A reference to data that has already been freed | Rust refuses to compile this — it catches it before your code runs |
| &'static str | A string slice that lives for the entire program lifetime | let s: &'static str = "hello"; — the value is baked into the binary |
| String slice [start..end] | A borrowed view into part of a String — returns &str; end index is excluded | &s[0..5] — the first 5 characters without taking ownership |
| push_str() | Appends a &str to a mutable String | s.push_str("_pro"); — adding multiple characters |
| push() | Appends a single char to a mutable String | s.push('!'); — adding one character |
| as_str() | Converts a String to a &str — borrows without moving | When a function expects &str but you have a String |
| .to_string() | Converts a &str to an owned String | "basic".to_string() — when you need to own a copy of a string literal |
| chars() | Returns an iterator over the individual characters of a string | for c in s.chars() { ... } — the safe way to loop over characters |
| Slice &[T] | A borrowed view into part of a collection — does not take ownership | &arr[1..3] — borrows elements 1 and 2 from an array |
| Array [T; N] | A fixed-size collection where every element is the same type — length is part of the type | [i32; 5] — an array of 5 integers; length must be known at compile time |
| .get(i) | Returns Option<&T> for an index — safe access that returns None instead of panicking | arr.get(10) — use when the index might be out of bounds |
| Term | What it is | When it's used |
|---|---|---|
| mod | Declares a module | Every time you create or reference a module |
| pub mod helpers; | Tell Rust to include helpers.rs as a module | In main.rs or lib.rs when code is split into files |
| pub fn | A public function — callable from outside its module | Any function another file needs to use |
| Private by default | Everything inside a module is hidden unless pub is written | Default Rust behavior — you choose what is visible |
| :: | Module path separator | When navigating into a module: helpers::function_name |
| Path | The full address of a function: helpers::get_full_name | When calling a function from another module |
| Child module | A module declared inside another module | When you want to group within a module further |
| Inline module | pub mod name { ... } — body is right here, not a file | Small sub-groups that do not need their own file |
| File-backed module | pub mod name; — body is in name.rs | Most common for larger code — keeps files separate |
| Package | The whole project — what cargo new creates | The container for all your crates |
| Crate | A compilation unit — either binary or library | The unit Rust actually compiles |
| Binary crate | Built from main.rs — produces an executable you can run | Regular programs with fn main |
| Library crate | Built from lib.rs — no fn main | Reusable code and every Anchor program |
| Crate root | The starting file for compilation (main.rs or lib.rs) | Where absolute paths begin |
| crate:: | Start an absolute path at the crate root | When calling across modules — always correct even if code moves |
| super:: | Go up one module level | Calling a function in the parent module |
| use | Bring a path into scope as a shortcut | When you want to stop typing the full path every call |
| pub use | Bring into scope AND re-export it to callers | Making internal paths publicly accessible — Anchor uses this |
| as | Rename an import | When two imports share the same name |
| Nested path | use x::{a, b, c} — import multiple things from one parent | Keeps the import section tidy |
| Glob * | Import everything public from a path | use anchor_lang::prelude::* — one line for everything |
| Term | What it is | When it's used |
|---|---|---|
| Struct | A custom type that groups named fields together | Defining account data, payment plans, subscribers |
| Field | One named value inside a struct | username: String, balance: u64 |
| Instance | A specific struct with actual values filled in | let user = User { username: "Alice", ... } |
| impl | Where you attach methods to a struct | Adding functions that belong to the struct |
| self | The current instance inside an impl block — &self reads, &mut self modifies | Inside any method on a struct |
| #[account] | Anchor macro that turns a struct into a serializable on-chain account | Every account that stores data on Solana |
| Enum | A type that can be exactly one of several named options | Subscription status, payment state, instruction results |
| Variant | One of the options inside an enum: Active, Expired | Matching or creating an enum value |
| match | Handles every variant of an enum — compiler enforces completeness | Branching on a Result, Option, or custom enum |
| Option<T> | Either Some(value) or None — Rust's way of saying "might not exist" | Any value that could be absent — replaces null |
| Result<T, E> | Either Ok(value) or Err(error) — success or failure | Any operation that can fail |
| #[error_code] | Anchor macro for defining custom program errors as an enum | When your program needs specific error messages |
| require! | Anchor macro for validation — returns your error if a condition fails | Checking conditions before processing a payment |
| Method | A function in an impl block that takes self, &self, or &mut self as its first parameter | wallet.deposit(amount) — the function belongs to the struct |
| &self | Gives read-only access to a struct instance inside a method | fn balance(&self) -> u64 — when the method only needs to read fields |
| &mut self | Gives mutable access to a struct instance inside a method | fn deposit(&mut self, amount: u64) — when the method needs to modify the struct |
| Associated function | A function in impl with no self parameter — called with :: not . | Wallet::new() — the idiomatic Rust constructor pattern |
| #[derive(Debug)] | An attribute that gives a struct or enum the ability to be printed with {:?} | Add above any struct you want to inspect during development |
| Field init shorthand | When a variable name matches a field name, you can write it once | User { email, username } instead of User { email: email, username: username } |
| Struct update syntax | ..other copies all remaining fields from an existing instance | let user2 = User { email: new_email, ..user1 }; |
| Vec<T> | A growable list where all elements are the same type | let mut v: Vec<u64> = Vec::new(); v.push(1_000_000); |
| Some(value) | The Option variant that contains a value | Some(42) — when the result is present |
| None | The Option variant that means no value — Rust's replacement for null | None — when there is nothing to return; must be handled explicitly |
| Ok(value) | The Result variant for success — holds the return value | Ok(new_balance) — the operation worked |
| Err(reason) | The Result variant for failure — holds the error reason | Err("Insufficient funds") — the operation failed; caller must handle it |
| Term | What it is | When it's used |
|---|---|---|
| Result<T, E> | Either Ok(value) or Err(error) — never both | Any function that can succeed or fail |
| Option<T> | Either Some(value) or None — Rust's version of "might not exist" | Any value that could be absent |
| ? operator | Propagates an error up — if Err, return it; if Ok, unwrap and continue | Inside functions that return Result — keeps code clean |
| require! | Anchor macro — check a condition, return a custom error if false | Validating payment amounts, account states, permissions |
| #[error_code] | Anchor attribute — marks an enum as a set of program error types | Defining all the ways your program can fail |
| Trait | Defines shared behavior — like an interface | When different types need to do the same thing |
| Display | Trait for how a type prints with {} | Implementing human-readable output |
| Debug | Trait for how a type prints with {:?} | Printing structs during development |
| Clone | Trait that makes an explicit copy of a value | When you need a duplicate of a struct |
| Copy | Trait for implicit copies — integers and booleans are Copy | Simple types that should copy automatically |
| PartialEq | Trait that allows == comparisons between two values | Testing whether two values are equal |
| AnchorSerialize | Converts a struct to bytes to store on-chain | Required on every Anchor account struct |
| AnchorDeserialize | Reads bytes from an account and rebuilds the struct | Required on every Anchor account struct |
| Default | Provides a zero or empty starting value for each field | Initializing account data with safe defaults |
| Generic <T> | A placeholder type — filled in when the code is actually used | Writing functions or structs that work with any type |
| Lifetime 'a | A label for how long a reference stays valid | Telling the compiler when a reference must still be alive |
| 'info | The standard lifetime name in Anchor context structs | Every Context<'info, T> in an Anchor instruction |
| Monomorphization | Rust compiles a separate version of generic code for each type used — no runtime cost | Happens automatically — explains why generics are fast |
| Recoverable error | An expected failure the program can handle and keep running | User overdraft, missing account, invalid input — use Result |
| Unrecoverable error | A programming mistake so severe the program cannot safely continue | Use panic! — the only safe response is to stop immediately |
| Error propagation | Passing an error up to the calling function with ? instead of handling it locally | When a function is not the right place to decide what to do with an error |
| Static dispatch | The compiler resolves the exact type at compile time — faster; no runtime overhead | impl Trait in function parameters |
| Dynamic dispatch | The type is resolved at runtime using a V-table — slightly slower but flexible | Box<dyn Trait> — needed when you do not know the type until runtime |
| Term | What it is | When it's used |
|---|---|---|
| Anchor | A framework for writing Solana programs — handles boilerplate and security checks automatically | Every Anchor program you write |
| #[program] | Marks the module that contains your instruction handlers | The main module in every Anchor program |
| #[account] | Turns a struct into an on-chain account with automatic serialization | Every struct that stores data on Solana |
| #[derive(Accounts)] | Generates account validation code for an instruction's input struct | Every instruction accounts struct |
| Context<T> | The first parameter of every instruction — holds all accounts and program data | Every instruction handler |
| ctx.accounts | Access the accounts passed into an instruction | Inside any instruction handler |
| Account<'info, T> | A validated, deserialized account of type T | When you want Anchor to check and load an account |
| Signer<'info> | An account that must have signed the transaction | Validating who is allowed to call an instruction |
| SystemProgram<'info> | The Solana system program — handles account creation | When creating new accounts |
| PDA | Program Derived Address — an account address controlled by your program, not a private key | Storing per-user state like subscriptions |
| seeds | The values used to derive a PDA address | #[account(seeds = [b"subscription", user.key().as_ref()])] |
| bump | A nonce added to make the PDA address valid — stored in the account | Part of every PDA derivation |
| init | Anchor constraint that creates a new account | When an instruction needs to set up a new on-chain account |
| mut constraint | Marks an account as writable — required to change its data | #[account(mut)] on any account you modify |
| has_one | Validates that one account's field matches another account's key | Checking that a subscription belongs to the right plan |
| close | Anchor constraint that closes an account and returns its rent to a wallet | When a subscription is cancelled |
| IDL | Interface Definition Language — the JSON file Anchor generates describing your program | Used by clients (TypeScript) to interact with the program |
| Lamport | The smallest unit of SOL — 1 SOL = 1,000,000,000 lamports | All payment amounts in Solana programs |
| Pubkey | A 32-byte public key — identifies a wallet or account on Solana | Storing addresses in account structs |
| transfer | Moves lamports from one account to another | Processing payments in a subscription program |
| Discriminator | 8 bytes Anchor adds to every account to identify its type | Automatic — prevents account confusion attacks |
| Space | The number of bytes to allocate when creating an account | space = 8 + 32 + 32 + 1 + 8 + 1 — must be exact |