Rust - Return Types
In Rust, the return type of a function specifies the type of value that the function will return. The return type
is indicated after the ->
symbol in the function signature. Rust supports a variety of return
types, including primitive types, complex types, and custom types.
1. Returning Primitive Types
A function can return basic data types like integers, floating-point numbers, booleans, and more.
Examples:
rustfn add(a: i32, b: i32) -> i32 {
a + b // No semicolon to return this expression's result
}
fn main() {
let result = add(5, 3);
println!("Result: {}", result); // Output: Result: 8
}
2. Returning Compound Types
Rust functions can return compound types such as tuples, arrays, or structs.
Returning Tuples:
rustfn swap(a: i32, b: i32) -> (i32, i32) {
(b, a)
}
fn main() {
let result = swap(1, 2);
println!("Swapped: {:?}", result); // Output: Swapped: (2, 1)
}
Returning Structs:
ruststruct Point {
x: i32,
y: i32,
}
fn create_point(x: i32, y: i32) -> Point {
Point { x, y }
}
fn main() {
let p = create_point(10, 20);
println!("Point: ({}, {})", p.x, p.y); // Output: Point: (10, 20)
}
3. Returning References
Functions can return references to values. When doing so, you need to manage lifetimes to ensure the returned reference is valid.
Example:
rustfn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
if s1.len() > s2.len() {
s1
} else {
s2
}
}
fn main() {
let string1 = String::from("long string");
let string2 = "short";
let result = longest(&string1, &string2);
println!("The longest string is {}", result); // Output: The longest string is long string
}
4. Returning Option
and Result
Types
Rust provides the Option
and Result
enums for returning values that might be optional
or involve error handling.
Returning Option
:
rustfn divide(a: f64, b: f64) -> Option<f64> {
if b == 0.0 {
None
} else {
Some(a / b)
}
}
fn main() {
match divide(4.0, 2.0) {
Some(result) => println!("Result: {}", result),
None => println!("Cannot divide by zero"),
}
}
Returning Result
:
rustfn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("Cannot divide by zero"))
} else {
Ok(a / b)
}
}
fn main() {
match divide(4.0, 0.0) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
}
5. Returning impl Trait
Rust allows functions to return types that implement a specific trait using the impl Trait
syntax.
This is useful for returning iterators or types that implement certain traits.
Example:
rustfn make_adder(x: i32) -> impl Fn(i32) -> i32 {
move |y| x + y
}
fn main() {
let add_five = make_adder(5);
println!("5 + 3 = {}", add_five(3)); // Output: 5 + 3 = 8
}
6. Returning ()
(Unit Type)
When a function doesn't return a value, it implicitly returns the unit type ()
.
Example:
rustfn greet() {
println!("Hello, world!");
// Implicitly returns ()
}
fn main() {
greet();
}
7. Early Returns Using return
Rust allows early returns using the return
keyword, which can be useful in certain scenarios like
error handling.
Example:
rustfn is_even(n: i32) -> bool {
if n % 2 == 0 {
return true; // Early return
}
false
}
fn main() {
println!("Is 4 even? {}", is_even(4)); // Output: Is 4 even? true
}
Summary
- Primitive types: Functions can return basic types like
i32
,f64
, etc. - Compound types: Functions can return tuples, arrays, structs, etc.
- References: Functions can return references with appropriate lifetimes.
- Option/Result types: Use
Option
for optional values andResult
for error handling. impl Trait
: Return types that implement specific traits.- Unit type
()
: Indicates no return value. - Early return: Use
return
to exit a function early.
Understanding return types in Rust helps you design more flexible and robust functions, especially when dealing with complex data and error handling.