Question
Is it possible to define a Rust function with default parameter values, similar to this?
fn add(a: int = 1, b: int = 2) {
a + b
}
If not, what is the Rust way to achieve similar behavior?
Short Answer
By the end of this page, you will understand that Rust does not support default function arguments directly. You will learn the common Rust alternatives, such as writing helper functions, using Option<T>, defining configuration structs with Default, and choosing clear APIs that match Rust's style.
Concept
Rust does not support default parameter values in function signatures.
In some languages, you can write a function once and let callers omit some arguments. Rust intentionally avoids this feature in favor of explicit APIs. This makes function calls easier to read and avoids ambiguity about which values are being passed.
For example, Rust does not allow this:
fn add(a: i32 = 1, b: i32 = 2) -> i32 {
a + b
}
Instead, Rust developers usually use one of these patterns:
- Create separate helper functions for common defaults
- Use
Option<T>when a parameter may or may not be provided - Use a struct with
Defaultwhen there are many configurable values - Provide constructor-like methods such as
new()andwith_x()
This matters in real programming because API design is a big part of writing maintainable Rust code. Rather than relying on hidden defaults in function signatures, Rust encourages you to make defaults visible and intentional.
Mental Model
Think of a Rust function call like filling out a paper form.
In some languages, you can leave fields blank and the system fills them in automatically. Rust usually prefers that you either:
- fill in every field clearly, or
- choose from a few well-defined forms, or
- submit a settings object that already contains sensible defaults.
So instead of saying, "This field is optional inside the function signature," Rust says, "Let's design the interface so defaults are obvious and explicit."
Syntax and Examples
1. Separate helper functions
This is the simplest Rust-style approach when there are only a few common combinations.
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn add_default() -> i32 {
add(1, 2)
}
fn add_with_a(a: i32) -> i32 {
add(a, 2)
}
fn main() {
println!("{}", add(5, 10));
println!("{}", add_default());
println!("{}", add_with_a(7));
}
Here:
addis the full functionadd_defaultuses both default values- lets you override one value
Step by Step Execution
Consider this example:
fn add(a: Option<i32>, b: Option<i32>) -> i32 {
let a = a.unwrap_or(1);
let b = b.unwrap_or(2);
a + b
}
fn main() {
let result = add(Some(10), None);
println!("{}", result);
}
Step by step:
maincallsadd(Some(10), None).- Inside
add, the parameteraisSome(10). a.unwrap_or(1)checks whetheracontains a value.- Since it is
Some(10), the result becomes .
Real World Use Cases
Common places this idea appears
Command-line tools
A CLI might accept optional flags. If the user does not provide a value, your program uses a sensible default.
fn run(port: Option<u16>) {
let port = port.unwrap_or(8080);
println!("Starting server on port {}", port);
}
Configuration objects
Applications often have many settings such as timeout, retries, and log level. A config struct with Default makes this manageable.
Constructors
A type might provide:
new()for standard defaultswith_capacity(...)or similar methods for customization
Library APIs
Rust libraries often avoid many positional arguments. Instead, they use:
- builder patterns
- option structs
- helper constructors
This keeps code readable as APIs grow.
Real Codebase Usage
In real Rust codebases, developers usually avoid trying to imitate default arguments too closely. Instead, they choose patterns that scale well.
Common patterns
Helper functions for common cases
Useful when there are only one or two default combinations.
fn connect(host: &str, port: u16) {
println!("Connecting to {}:{}", host, port);
}
fn connect_local() {
connect("localhost", 5432);
}
Guarding optional input with Option<T>
This is common when values truly may be absent.
fn fetch(limit: Option<usize>) {
let limit = limit.unwrap_or(100);
println!("Fetching up to {} items", limit);
}
Config structs with Default
This is common in libraries and applications.
Common Mistakes
1. Trying to write default values in the parameter list
This is not valid Rust.
fn add(a: i32 = 1, b: i32 = 2) -> i32 {
a + b
}
Use a helper function, Option<T>, or a config struct instead.
2. Using Option<T> when values are not truly optional
This works technically, but may make your API harder to use.
fn connect(host: Option<&str>, port: Option<u16>) {
let host = host.unwrap_or("localhost");
let port = port.unwrap_or(5432);
}
If every caller almost always uses defaults, a config struct or helper function may be clearer.
3. Deriving Default when the generated values are wrong
This code compiles, but 0 may not be the default you want.
Comparisons
| Approach | Best for | Pros | Cons |
|---|---|---|---|
| Helper functions | A few common defaults | Simple and readable | Can multiply into many functions |
Option<T> parameters | Truly optional values | Flexible | Calls can become noisy with Some(...) and None |
Struct + Default | Many settings | Scales well, self-documenting | More code than a tiny function |
| Builder pattern | Complex configuration | Very readable for many optional fields | More setup code |
Option<T> vs config struct
Cheat Sheet
// Rust does NOT support default function arguments
fn add(a: i32, b: i32) -> i32 {
a + b
}
Common replacements
1. Helper function
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn add_default() -> i32 {
add(1, 2)
}
2. Option<T>
fn add(a: Option<i32>, b: Option<i32>) -> i32 {
a.unwrap_or(1) + b.unwrap_or(2)
}
3. Struct with Default
FAQ
Does Rust support default function parameters?
No. Rust does not allow default values in function parameter lists.
What is the Rust alternative to default arguments?
Common alternatives are helper functions, Option<T>, config structs with Default, and builder patterns.
Should I use Option<T> to simulate default arguments?
Only when the value is genuinely optional. If many settings need defaults, a struct is usually clearer.
How do I set custom default values in Rust?
Implement the Default trait manually:
impl Default for MyType {
fn default() -> Self {
Self { /* custom values */ }
}
}
Why doesn't Rust include default arguments?
Rust generally prefers explicit function calls and clear API design over hidden behavior in parameter lists.
Is a builder pattern better than Option<T>?
For complex configuration, yes. Builders are often easier to read and maintain.
Can I overload functions in Rust like other languages?
Mini Project
Description
Build a small Rust program that calculates the price of an order using sensible defaults. This demonstrates how to replace default function arguments with a configuration struct and the Default trait.
Goal
Create a function that calculates a final price while allowing callers to override only the settings they care about.
Requirements
- Create a struct to store pricing options.
- Implement
Defaultwith meaningful values. - Write a function that uses the options struct to calculate a total.
- Show one call using all defaults and another overriding only one field.
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Fixing Rust "linker 'cc' not found" on Debian in WSL
Learn why Rust shows "linker 'cc' not found" on Debian in WSL and how to fix it by installing the required C build tools.
Handling Errors While Mapping Iterators in Rust
Learn how to stop iterator processing and return errors in Rust using collect, Result, and iterator patterns.