A move in Rust transfers ownership of a value from one variable to another, invalidating the original variable. This happens automatically when you pass non-Copy types (like String) to functions or assign them to new variables.
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 is moved into s2; s1 is no longer valid
// println!("{s1}"); // Error: borrow of moved value
println!("{s2}"); // Valid
}
Simple types like i32 implement the Copy trait, so they are duplicated instead of moved.