278: Getting the Last Element with last()
Functional Programming
Tutorial
The Problem
Retrieving the final element of a sequence is straightforward for slices (slice.last()) but requires consuming the entire iterator for non-indexed collections. The last() method provides a safe, idiomatic way to get the final element of any iterator, returning Option<T> to handle the empty case. Combined with filter(), it finds the last matching element in a single pass.
🎯 Learning Outcomes
last() must consume the entire iterator to find the final elementlast() after filter() to find the last matching elementlast() on a DoubleEndedIterator (like slice iterators) can optimize to O(1)last() from iterator last() — same semantics, different implementationsCode Example
//! 278. Getting the last element
//!
//! `last()` consumes the iterator to return `Option<T>` with the final element.
/// Returns the last element of a slice, or `None` if empty.
pub fn last<T>(slice: &[T]) -> Option<&T> {
slice.last()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_last_basic() {
let v = [1i32, 2, 3, 4, 5];
assert_eq!(last(&v), Some(&5));
}
#[test]
fn test_last_empty() {
let empty: &[i32] = &[];
assert_eq!(last(empty), None);
}
#[test]
fn test_last_single() {
assert_eq!(last(&[42i32]), Some(&42));
}
#[test]
fn test_last_words() {
let words = ["apple", "banana", "cherry"];
assert_eq!(last(&words), Some(&"cherry"));
}
#[test]
fn test_last_after_filter_iter() {
let last_even = (1i32..=10).filter(|x| x % 2 == 0).last();
assert_eq!(last_even, Some(10));
}
#[test]
fn test_last_after_filter_collect() {
let nums = vec![1i32, 2, 3, 4, 5];
let evens: Vec<i32> = nums.into_iter().filter(|x| x % 2 == 0).collect();
assert_eq!(last(&evens), Some(&4));
}
}Key Differences
last() on DoubleEndedIterator can call next_back() for O(1) access; OCaml has no equivalent built-in optimization.last() keeps only one element in memory at a time; OCaml's List.rev allocates a full reversed list.filter().last() is the clean Rust idiom; OCaml requires List.filter + last — two separate operations.OCaml Approach
OCaml's standard library provides List.rev then List.hd for the last element, though this allocates a reversed list. More efficient is a fold:
let last = function [] -> None | xs -> Some (List.nth xs (List.length xs - 1))
(* Or more efficiently: *)
let last lst = List.fold_left (fun _ x -> Some x) None lst
List.hd (List.rev lst) is common but allocates; the fold approach is O(n) without allocation.
Full Source
//! 278. Getting the last element
//!
//! `last()` consumes the iterator to return `Option<T>` with the final element.
/// Returns the last element of a slice, or `None` if empty.
pub fn last<T>(slice: &[T]) -> Option<&T> {
slice.last()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_last_basic() {
let v = [1i32, 2, 3, 4, 5];
assert_eq!(last(&v), Some(&5));
}
#[test]
fn test_last_empty() {
let empty: &[i32] = &[];
assert_eq!(last(empty), None);
}
#[test]
fn test_last_single() {
assert_eq!(last(&[42i32]), Some(&42));
}
#[test]
fn test_last_words() {
let words = ["apple", "banana", "cherry"];
assert_eq!(last(&words), Some(&"cherry"));
}
#[test]
fn test_last_after_filter_iter() {
let last_even = (1i32..=10).filter(|x| x % 2 == 0).last();
assert_eq!(last_even, Some(10));
}
#[test]
fn test_last_after_filter_collect() {
let nums = vec![1i32, 2, 3, 4, 5];
let evens: Vec<i32> = nums.into_iter().filter(|x| x % 2 == 0).collect();
assert_eq!(last(&evens), Some(&4));
}
}
✓ Tests
Rust test suite
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_last_basic() {
let v = [1i32, 2, 3, 4, 5];
assert_eq!(last(&v), Some(&5));
}
#[test]
fn test_last_empty() {
let empty: &[i32] = &[];
assert_eq!(last(empty), None);
}
#[test]
fn test_last_single() {
assert_eq!(last(&[42i32]), Some(&42));
}
#[test]
fn test_last_words() {
let words = ["apple", "banana", "cherry"];
assert_eq!(last(&words), Some(&"cherry"));
}
#[test]
fn test_last_after_filter_iter() {
let last_even = (1i32..=10).filter(|x| x % 2 == 0).last();
assert_eq!(last_even, Some(10));
}
#[test]
fn test_last_after_filter_collect() {
let nums = vec![1i32, 2, 3, 4, 5];
let evens: Vec<i32> = nums.into_iter().filter(|x| x % 2 == 0).collect();
assert_eq!(last(&evens), Some(&4));
}
}
Exercises
Vec<String>) that matches a warning pattern.VecDeque as a sliding window.last() and fold(None, |_, x| Some(x)) produce identical results.