8.16 Summary

This chapter provided a comprehensive look at functions and methods in Rust, contrasting them with C/C++ where relevant. Key takeaways include:

  • main Function: The mandatory entry point, can return () or Result<(), E>.
  • Definition and Calling: Use fn, no forward declarations needed within a module. Calls require (). Arguments are comma-separated.
  • Parameters & Data Passing: Ownership transfer (T), immutable borrow (&T), mutable borrow (&mut T). Copy types are copied. Choose based on ownership and modification needs. mut T params don’t require mut on the caller’s variable.
  • Return Values: Use -> Type. Implicit return via the last expression (no semicolon) is idiomatic; explicit return for early exits.
  • Lifetimes: Required when returning references (&T, &mut T) to ensure validity; Rust prevents returning references to local variables.
  • Scope: Top-level functions visible within their module (pub for external visibility). Nested functions are local to their outer function and cannot capture environment variables.
  • No Default/Named Parameters: Use Option<T> or the Builder pattern instead.
  • Slices & Tuples: Efficient for passing views (&str, &[T]) or returning multiple values (T, U). Unsized types str and [T] exist but are used behind pointers.
  • Generics: Use <T: Trait> for type-polymorphic functions, enabling source code reuse with type safety (monomorphized at compile time).
  • Function Pointers & HOFs: fn(Args) -> Ret type allows passing functions as data. Higher-order functions accept or return functions/closures. Rust function pointers are safe.
  • Recursion & TCO: Recursion is supported, but Rust provides no guarantee of Tail Call Optimization (TCO), so deep recursion risks stack overflow. Prefer iteration or explicit stack simulation for potentially unbounded depths.
  • Inlining: Compiler optimization (#[inline] hints) to reduce call overhead and enable further optimizations. Limited by various factors (opt level, call type, boundaries, heuristics). LTO can enable more inlining.
  • Methods & Associated Functions: Defined in impl blocks. Methods operate on instances (self, &self, &mut self, using Self type); associated functions belong to the type (Type::func()), often used for constructors. Auto-referencing simplifies method calls.
  • No Function Overloading: Use generics or traits for polymorphism.
  • Return Type Inference: Limited; explicit return types required except for impl Trait.
  • Variadics: No direct support; use macros for type-safe variable argument handling.
  • Ignoring Returns: Allowed, but #[must_use] warns if potentially important values (like Result) are ignored. Use let _ = ...; for explicit discard.

Functions and methods are central to structuring Rust code safely and efficiently. Understanding ownership, borrowing, lifetimes, and the various ways functions interact with data forms the bedrock for writing effective Rust programs. Later chapters will build on this foundation, exploring closures, asynchronous functions, and advanced trait patterns.