Closures are one of the core concepts and most elegant features of functional programming. Experience the magic of closures in Topaz! ✨
🌱 Basic Concepts of Closures
What are Closures?
A closure is a function that can remember and access variables from the environment where it was defined. It's called a closure because the function "closes over" and carries the environment (scope) from when it was created.
// Basic closure example
function outerFunction(outerVariable: int) -> impl Fn(int) -> int {
// Create closure - captures outerVariable
let innerFunction = |innerVariable: int| -> int {
outerVariable + innerVariable // Accessing variable from outer scope
}
return innerFunction
}
// Closure counter example
function createCounter(initialValue: int) -> impl Fn() -> int {
let mut currentValue = initialValue
// Closure that captures currentValue
return move || -> int {
currentValue += 1
currentValue
}
}
// Multiplier function generator
function createMultiplier(multiplier: int) -> impl Fn(int) -> int {
|value: int| value * multiplier
} test {
// Test outer function
let add5 = outerFunction(5)
assert add5(3) == 8
assert add5(10) == 15
// Test counter
let mut counter1 = createCounter(0)
let mut counter2 = createCounter(100)
assert counter1() == 1
assert counter1() == 2
assert counter2() == 101
assert counter1() == 3 // Independent state maintained
// Test multiplier generator
let doubler = createMultiplier(2)
let tripler = createMultiplier(3)
assert doubler(5) == 10
assert tripler(4) == 12
}
print("add5(7) = {outerFunction(5)(7)}")
let mut myCounter = createCounter(10)
print("Counter: {myCounter()}, {myCounter()}, {myCounter()}")
let tenMultiplier = createMultiplier(10)
print("10 * 7 = {tenMultiplier(7)}")
Core Characteristics of Closures
- Environment Capture: Remembers variables from outer scopes
- State Preservation: Maintains state between function calls
- Lazy Execution: Defers computation until needed
- Code Reuse: Same logic applicable in various contexts
🎨 Various Closure Patterns
Value Capture vs Reference Capture
// Value capture (Copy)
function valueCaptureExample() -> impl Fn() -> int {
let value = 42
// Value is copied into closure
|| value // Value is copied inside closure
}
// Reference capture (Borrow)
function referenceCaptureExample() -> impl Fn() -> int {
let value = 42
// Capture by reference (when lifetime allows)
move || value // Transfer ownership with move keyword
}
// Mutable reference capture
function mutableCaptureExample() -> impl FnMut() -> int {
let mut count = 0
// Capture mutable reference
move || -> int {
count += 1
count
}
}
// Complex environment capture
function complexEnvironment() -> (impl Fn(int) -> int, impl Fn(int) -> int) {
let baseValue = 10
let multiplier = 3
let mut accumulatedValue = 0
let addFunction = move |additionalValue: int| -> int {
accumulatedValue += additionalValue
baseValue + accumulatedValue
}
let multiplyFunction = |inputValue: int| -> int {
inputValue * multiplier
}
return (addFunction, multiplyFunction)
}
// Closure chaining
function createFunctionChain(initialFunction: impl Fn(int) -> int) -> impl Fn(impl Fn(int) -> int) -> impl Fn(int) -> int {
move |nextFunction: impl Fn(int) -> int| -> impl Fn(int) -> int {
move |input: int| -> int {
nextFunction(initialFunction(input))
}
}
} test {
// Value capture test
let valueClosure = valueCaptureExample()
assert valueClosure() == 42
// Mutable capture test
let mut mutableClosure = mutableCaptureExample()
assert mutableClosure() == 1
assert mutableClosure() == 2
assert mutableClosure() == 3
// Complex environment test
let (mut addFunction, multiplyFunction) = complexEnvironment()
assert addFunction(5) == 15 // 10 + 5
assert addFunction(3) == 18 // 10 + 5 + 3
assert multiplyFunction(4) == 12 // 4 * 3
// Function chaining test
let double = |x: int| x * 2
let add10 = |x: int| x + 10
let chainedFunction = createFunctionChain(double)(add10)
assert chainedFunction(5) == 20 // (5 * 2) + 10
}
let mut myMutableClosure = mutableCaptureExample()
print("Mutable closure: {myMutableClosure()}, {myMutableClosure()}")
let (mut addFunction, multiplyFunction) = complexEnvironment()
print("Add: {addFunction(7)}, Multiply: {multiplyFunction(6)}")
Higher-Order Functions and Closures
// Function that returns a function
function conditionalFunctionCreator(condition: bool) -> impl Fn(int) -> int {
if condition {
|x: int| x * 2 // Double
} else {
|x: int| x + 10 // Add 10
}
}
// Function that takes a function as parameter
function functionApplier<F, T>(value: T, function: F) -> T
where
F: Fn(T) -> T
{
function(value)
}
// Composer that combines multiple functions
function functionComposer<F, G, T>(function1: F, function2: G) -> impl Fn(T) -> T
where
F: Fn(T) -> T,
G: Fn(T) -> T,
T: 'static
{
move |input: T| -> T {
function2(function1(input))
}
}
// Currying implementation
function curryingExample(a: int) -> impl Fn(int) -> impl Fn(int) -> int {
move |b: int| -> impl Fn(int) -> int {
move |c: int| -> int {
a + b + c
}
}
}
// Memoization closure
function memoization<F, T, U>(function: F) -> impl FnMut(T) -> U
where
F: Fn(T) -> U,
T: Clone + std::hash::Hash + Eq,
U: Clone,
{
use std::collections::HashMap
let mut cache: HashMap<T, U> = HashMap::new()
move |input: T| -> U {
match cache.get(&input) { case Some(result) => return result.clone(), case None => {} }
let result = function(input.clone())
cache.insert(input, result.clone())
result
}
} test {
// Conditional function creator test
let doubleFunction = conditionalFunctionCreator(true)
let addFunction = conditionalFunctionCreator(false)
assert doubleFunction(5) == 10
assert addFunction(5) == 15
// Function applier test
let result = functionApplier(10, |x| x * 3)
assert result == 30
// Function composer test
let add5 = |x: int| x + 5
let multiply2 = |x: int| x * 2
let composedFunction = functionComposer(add5, multiply2)
assert composedFunction(3) == 16 // (3 + 5) * 2
// Currying test
let curriedFunction = curryingExample(1)(2)(3)
assert curriedFunction == 6 // 1 + 2 + 3
// Memoization test
let mut memoFactorial = memoization(|n: int| -> int {
if n <= 1 { 1 } else { n * memoFactorial(n - 1) }
})
assert memoFactorial(5) == 120
}
print("Conditional(true): {conditionalFunctionCreator(true)(7)}")
print("Composed function result: {functionComposer(|x| x + 1, |x| x * 10)(4)}")
print("Currying result: {curryingExample(10)(20)(30)}")
Event Handling and Callbacks
// Event handler type definition
type EventHandler<T> = Box<dyn FnMut(T)>
// Simple event system
struct EventSystem<T> {
handlers: Vec<EventHandler<T>>
}
impl<T> EventSystem<T>
where
T: Clone
{
function new() -> Self {
EventSystem {
handlers: Vec::new()
}
}
// Register event handler
function registerHandler<F>(&mut self, handler: F)
where
F: FnMut(T) + 'static
{
self.handlers.push(Box::new(handler))
}
// Trigger event
function triggerEvent(&mut self, data: T) {
for handler in &mut self.handlers {
handler(data.clone())
}
}
}
// Async operation simulation
function asyncOperation<F>(delayMs: int, completionCallback: F)
where
F: FnOnce(string) + 'static
{
// In reality this would be async, but here we execute immediately
let result = format!("Task completed (after {}ms)", delayMs)
completionCallback(result)
}
// State change detector
struct StateWatcher<T> {
currentState: T,
changeCallbacks: Vec<Box<dyn Fn(&T, &T)>>
}
impl<T> StateWatcher<T>
where
T: Clone + PartialEq
{
function new(initialState: T) -> Self {
StateWatcher {
currentState: initialState,
changeCallbacks: Vec::new()
}
}
function registerChangeCallback<F>(&mut self, callback: F)
where
F: Fn(&T, &T) + 'static
{
self.changeCallbacks.push(Box::new(callback))
}
function changeState(&mut self, newState: T) {
if self.currentState != newState {
let previousState = self.currentState.clone()
self.currentState = newState.clone()
for callback in &self.changeCallbacks {
callback(&previousState, &newState)
}
}
}
function currentValue(&self) -> &T {
&self.currentState
}
} test {
// Event system test
let mut eventSystem = EventSystem::<string>::new()
let mut receivedMessages: Vec<string> = Vec::new()
eventSystem.registerHandler(move |message: string| {
receivedMessages.push(format!("Handler1: {}", message))
})
eventSystem.registerHandler(|message: string| {
println!("Handler2 received: {}", message)
})
eventSystem.triggerEvent("Test message".to_string())
// State watcher test
let mut temperatureWatcher = StateWatcher::new(20.0)
let mut changeLog: Vec<string> = Vec::new()
temperatureWatcher.registerChangeCallback(move |previous: &f64, newValue: &f64| {
changeLog.push(format!("Temperature change: {}°C → {}°C", previous, newValue))
})
temperatureWatcher.changeState(25.0)
temperatureWatcher.changeState(30.0)
assert *temperatureWatcher.currentValue() == 30.0
}
// Usage example
let mut clickEvent = EventSystem::<string>::new()
clickEvent.registerHandler(|buttonName: string| {
print!("Button '{}' was clicked!", buttonName)
})
clickEvent.triggerEvent("OK".to_string())
// Async operation example
asyncOperation(1000, |result: string| {
print!("Async operation result: {}", result)
})
🚀 Practical Closure Applications
Functional Programming Patterns
// Functional pipeline
function pipeline<T>(initialValue: T) -> PipelineBuilder<T> {
PipelineBuilder::new(initialValue)
}
struct PipelineBuilder<T> {
value: T
}
impl<T> PipelineBuilder<T> {
function new(value: T) -> Self {
PipelineBuilder { value }
}
function map<U, F>(self, function: F) -> PipelineBuilder<U>
where
F: FnOnce(T) -> U
{
PipelineBuilder::new(function(self.value))
}
function filter<F>(self, condition: F) -> Option<PipelineBuilder<T>>
where
F: FnOnce(&T) -> bool
{
if condition(&self.value) {
Some(self)
} else {
None
}
}
function fold<U, F>(self, initialValue: U, function: F) -> U
where
F: FnOnce(U, T) -> U
{
function(initialValue, self.value)
}
function finish(self) -> T {
self.value
}
}
// Array processing utility
function arrayProcessor<T>() -> ArrayProcessor<T> {
ArrayProcessor::new()
}
struct ArrayProcessor<T> {
_phantom: std::marker::PhantomData<T>
}
impl<T> ArrayProcessor<T> {
function new() -> Self {
ArrayProcessor { _phantom: std::marker::PhantomData }
}
function map<U, F>(&self, array: Vec<T>, function: F) -> Vec<U>
where
F: Fn(T) -> U
{
array.into_iter().map(function).collect()
}
function filter<F>(&self, array: Vec<T>, condition: F) -> Vec<T>
where
F: Fn(&T) -> bool
{
array.into_iter().filter(condition).collect()
}
function reduce<F>(&self, array: Vec<T>, function: F) -> Option<T>
where
F: Fn(T, T) -> T
{
array.into_iter().reduce(function)
}
function fold<U, F>(&self, array: Vec<T>, initialValue: U, function: F) -> U
where
F: Fn(U, T) -> U
{
array.into_iter().fold(initialValue, function)
}
}
// Conditional execution chain
function ifCondition<F>(condition: bool, executeFunction: F) -> ConditionalExecution<F>
where
F: FnOnce()
{
ConditionalExecution { condition, executeFunction: Some(executeFunction) }
}
struct ConditionalExecution<F>
where
F: FnOnce()
{
condition: bool,
executeFunction: Option<F>
}
impl<F> ConditionalExecution<F>
where
F: FnOnce()
{
function otherwise<G>(mut self, elseFunction: G)
where
G: FnOnce()
{
if self.condition {
match self.executeFunction.take() { case Some(function) => function(), case None => {} }
} else {
elseFunction()
}
}
function execute(mut self) {
if self.condition {
match self.executeFunction.take() { case Some(function) => function(), case None => {} }
}
}
} test {
// Pipeline test
let result = pipeline(10)
.map(|x| x * 2)
.map(|x| x + 5)
.filter(|&x| x > 20)
.map(|x| x.to_string())
.finish()
assert result == Some("25".to_string())
// Array processor test
let arrayProcessor = arrayProcessor::<i32>()
let numbers = vec![1, 2, 3, 4, 5]
let squares = arrayProcessor.map(numbers.clone(), |x| x * x)
assert squares == vec![1, 4, 9, 16, 25]
let evens = arrayProcessor.filter(numbers.clone(), |&x| x % 2 == 0)
assert evens == vec![2, 4]
let sum = arrayProcessor.fold(numbers, 0, |acc, x| acc + x)
assert sum == 15
// Conditional execution test
let mut executed = false
ifCondition(true, || {
executed = true
}).execute()
assert executed == true
}
// Usage example
let processResult = pipeline(vec![1, 2, 3, 4, 5])
.map(|array| arrayProcessor::<i32>().map(array, |x| x * 2))
.map(|array| arrayProcessor::<i32>().filter(array, |&x| x > 5))
.finish()
print!("Processed array: {:?}", processResult)
ifCondition(processResult.len() > 2, || {
print!("Array is sufficiently large!")
}).otherwise(|| {
print!("Array is too small.")
})
Lazy Evaluation and Streams
// Lazy evaluation sequence
struct LazySequence<T, F>
where
F: Fn() -> Option<T>
{
generatorFunction: F
}
impl<T, F> LazySequence<T, F>
where
F: Fn() -> Option<T>
{
function new(generatorFunction: F) -> Self {
LazySequence { generatorFunction }
}
function take(self, count: usize) -> Vec<T> {
let mut result = Vec::new()
for _ in 0..count {
match (self.generatorFunction)() { case Some(value) => result.push(value), case None => break }
}
result
}
}
// Infinite sequence generator
function infiniteSequence(start: int, step: int) -> impl Fn() -> Option<int> {
let mut current = start
move || -> Option<int> {
let value = current
current += step
Some(value)
}
}
// Fibonacci sequence generator
function fibonacciGenerator() -> impl Fn() -> Option<int> {
let mut a = 0
let mut b = 1
move || -> Option<int> {
let current = a
let next = a + b
a = b
b = next
Some(current)
}
}
// Conditional infinite sequence
function conditionalSequence<F, P>(generatorFunction: F, condition: P) -> impl Fn() -> Option<int>
where
F: Fn() -> int,
P: Fn(int) -> bool
{
move || -> Option<int> {
loop {
let value = generatorFunction()
if condition(value) {
return Some(value)
}
}
}
}
// Stream processor
struct Stream<T> {
data: Vec<T>
}
impl<T> Stream<T>
where
T: Clone
{
function from(data: Vec<T>) -> Self {
Stream { data }
}
function map<U, F>(self, function: F) -> Stream<U>
where
F: Fn(T) -> U
{
Stream {
data: self.data.into_iter().map(function).collect()
}
}
function filter<F>(self, condition: F) -> Stream<T>
where
F: Fn(&T) -> bool
{
Stream {
data: self.data.into_iter().filter(condition).collect()
}
}
function take(self, count: usize) -> Stream<T> {
Stream {
data: self.data.into_iter().take(count).collect()
}
}
function collect(self) -> Vec<T> {
self.data
}
} test {
// Infinite sequence test
let arithmeticSequence = infiniteSequence(1, 2) // 1, 3, 5, 7, ...
let firstFive = (0..5).map(|_| arithmeticSequence()).collect::<Vec<_>>()
assert firstFive == vec![Some(1), Some(3), Some(5), Some(7), Some(9)]
// Fibonacci test
let fibonacci = fibonacciGenerator()
let firstSixFibonacci: Vec<_> = (0..6).map(|_| fibonacci()).collect()
assert firstSixFibonacci == vec![Some(0), Some(1), Some(1), Some(2), Some(3), Some(5)]
// Stream processing test
let result = Stream::from(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
.filter(|&x| x % 2 == 0) // Even numbers only
.map(|x| x * x) // Square
.take(3) // First 3
.collect()
assert result == vec![4, 16, 36] // 2², 4², 6²
}
// Usage example
let oddGenerator = infiniteSequence(1, 2)
print!("First 10 odd numbers: {:?}", (0..<10).map(|_| oddGenerator()).collect::<Vec<_>>())
let fibonacci = fibonacciGenerator()
print!("Fibonacci sequence: {:?}", (0..8).map(|_| fibonacci()).collect::<Vec<_>>())
let streamResult = Stream::from((1..=20).collect())
.filter(|&x| x % 3 == 0) // Multiples of 3
.map(|x| format!("{}th", x)) // String conversion
.take(4)
.collect()
print!("Multiples of 3: {:?}", streamResult)
🎯 Advanced Closure Techniques
Dynamic Function Generation
// Runtime function generator
enum OperationType {
Add,
Subtract,
Multiply,
Divide
}
function createOperationFunction(operation: OperationType, operand: f64) -> Box<dyn Fn(f64) -> f64> {
match operation {
case OperationType::Add => Box::new(move |x| x + operand),
case OperationType::Subtract => Box::new(move |x| x - operand),
case OperationType::Multiply => Box::new(move |x| x * operand),
case OperationType::Divide => Box::new(move |x| {
if operand != 0.0 { x / operand } else { f64::NAN }
})
}
}
// Conditional function chain
struct FunctionChain<T> {
functions: Vec<Box<dyn Fn(T) -> T>>
}
impl<T> FunctionChain<T>
where
T: 'static
{
function new() -> Self {
FunctionChain { functions: Vec::new() }
}
function add<F>(mut self, function: F) -> Self
where
F: Fn(T) -> T + 'static
{
self.functions.push(Box::new(function))
self
}
function conditionalAdd<F>(mut self, condition: bool, function: F) -> Self
where
F: Fn(T) -> T + 'static
{
if condition {
self.functions.push(Box::new(function))
}
self
}
function execute(self, initialValue: T) -> T {
self.functions.into_iter().fold(initialValue, |value, function| function(value))
}
}
// Configurable validator generator
struct ValidationRule<T> {
name: string,
validationFunction: Box<dyn Fn(&T) -> bool>
}
struct Validator<T> {
rules: Vec<ValidationRule<T>>
}
impl<T> Validator<T> {
function new() -> Self {
Validator { rules: Vec::new() }
}
function addRule<F>(mut self, name: string, validationFunction: F) -> Self
where
F: Fn(&T) -> bool + 'static
{
self.rules.push(ValidationRule {
name,
validationFunction: Box::new(validationFunction)
})
self
}
function validate(&self, value: &T) -> Result<(), Vec<string>> {
let mut errors = Vec::new()
for rule in &self.rules {
if !(rule.validationFunction)(value) {
errors.push(rule.name.clone())
}
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
} test {
// Dynamic function generation test
let add10 = createOperationFunction(OperationType::Add, 10.0)
let multiply2 = createOperationFunction(OperationType::Multiply, 2.0)
assert add10(5.0) == 15.0
assert multiply2(7.0) == 14.0
// Function chain test
let chain = FunctionChain::new()
.add(|x: i32| x + 1)
.conditionalAdd(true, |x: i32| x * 2)
.add(|x: i32| x - 3)
let result = chain.execute(5) // ((5 + 1) * 2) - 3 = 9
assert result == 9
// Validator test
let numberValidator = Validator::new()
.addRule("must be positive".to_string(), |&x: &i32| x > 0)
.addRule("must be less than 100".to_string(), |&x: &i32| x < 100)
.addRule("must be even".to_string(), |&x: &i32| x % 2 == 0)
assert numberValidator.validate(&50).is_ok()
assert numberValidator.validate(&-5).is_err()
assert numberValidator.validate(&51).is_err() // Fails because it's odd
}
// Usage example
let calculationChain = FunctionChain::new()
.add(|x: f64| x * 1.5) // 50% increase
.conditionalAdd(true, |x| x + 10.0) // Add 10
.add(|x| x.round()) // Round
let finalResult = calculationChain.execute(7.3)
print!("Calculation result: {}", finalResult)
let stringValidator = Validator::new()
.addRule("not empty".to_string(), |s: &string| !s.is_empty())
.addRule("minimum length".to_string(), |s: &string| s.len() >= 3)
.addRule("contains special char".to_string(), |s: &string| s.contains('@'))
match stringValidator.validate(&"test@example.com".to_string()) {
case Ok(()) => print!("Validation successful!"),
case Err(errors) => print!("Validation failed: {:?}", errors)
}
Plugin System
// Plugin interface
trait Plugin {
function name(&self) -> &str
function execute(&self, input: &str) -> string
}
// Closure-based plugin
struct ClosurePlugin<F>
where
F: Fn(&str) -> string
{
name: string,
executeFunction: F
}
impl<F> ClosurePlugin<F>
where
F: Fn(&str) -> string
{
function new(name: string, executeFunction: F) -> Self {
ClosurePlugin { name, executeFunction }
}
}
impl<F> Plugin for ClosurePlugin<F>
where
F: Fn(&str) -> string
{
function name(&self) -> &str {
&self.name
}
function execute(&self, input: &str) -> string {
(self.executeFunction)(input)
}
}
// Plugin manager
struct PluginManager {
plugins: Vec<Box<dyn Plugin>>
}
impl PluginManager {
function new() -> Self {
PluginManager { plugins: Vec::new() }
}
function registerPlugin<P>(mut self, plugin: P) -> Self
where
P: Plugin + 'static
{
self.plugins.push(Box::new(plugin))
self
}
function executeAllPlugins(&self, input: &str) -> Vec<(string, string)> {
self.plugins
.iter()
.map(|plugin| (plugin.name().to_string(), plugin.execute(input)))
.collect()
}
function findPlugin(&self, name: &str) -> Option<&dyn Plugin> {
self.plugins
.iter()
.find(|plugin| plugin.name() == name)
.map(|plugin| plugin.as_ref())
}
}
// Middleware system
type Middleware<T> = Box<dyn Fn(T, Box<dyn Fn(T) -> T>) -> T>
struct MiddlewareChain<T> {
middlewares: Vec<Middleware<T>>
}
impl<T> MiddlewareChain<T>
where
T: 'static
{
function new() -> Self {
MiddlewareChain { middlewares: Vec::new() }
}
function addMiddleware<F>(mut self, middleware: F) -> Self
where
F: Fn(T, Box<dyn Fn(T) -> T>) -> T + 'static
{
self.middlewares.push(Box::new(middleware))
self
}
function execute<F>(self, input: T, finalHandler: F) -> T
where
F: Fn(T) -> T + 'static
{
let mut chain = Box::new(finalHandler) as Box<dyn Fn(T) -> T>
for middleware in self.middlewares.into_iter().rev() {
let previousChain = chain
chain = Box::new(move |input| middleware(input, previousChain))
}
chain(input)
}
} test {
// Plugin system test
let manager = PluginManager::new()
.registerPlugin(ClosurePlugin::new(
"uppercase".to_string(),
|text| text.to_uppercase()
))
.registerPlugin(ClosurePlugin::new(
"length counter".to_string(),
|text| format!("Length: {}", text.len())
))
.registerPlugin(ClosurePlugin::new(
"reverse".to_string(),
|text| text.chars().rev().collect()
))
let results = manager.executeAllPlugins("hello world")
assert results.len() == 3
match manager.findPlugin("uppercase") { case Some(uppercasePlugin) => assert uppercasePlugin.execute("test") == "TEST", case None => {} }
// Middleware test
let chain = MiddlewareChain::new()
.addMiddleware(|value: i32, next| {
print!("Middleware 1: input {}", value)
let result = next(value + 1)
print!("Middleware 1: output {}", result)
result
})
.addMiddleware(|value, next| {
print!("Middleware 2: input {}", value)
let result = next(value * 2)
print!("Middleware 2: output {}", result)
result
})
let finalResult = chain.execute(5, |value| {
print!("Final handler: {}", value)
value + 10
})
assert finalResult == 22 // ((5 + 1) * 2) + 10
}
// Usage example
let textProcessingManager = PluginManager::new()
.registerPlugin(ClosurePlugin::new(
"HTML escape".to_string(),
|text| text.replace("&", "&").replace("<", "<").replace(">", ">")
))
.registerPlugin(ClosurePlugin::new(
"markdown emphasis".to_string(),
|text| format!("**{}**", text)
))
let processingResults = textProcessingManager.executeAllPlugins("Hello <world> & friends!")
for (pluginName, result) in processingResults {
print!("{}: {}", pluginName, result)
}
�� Closure Performance Optimization
Memory-Efficient Closures
// Reference-based closure (memory efficient)
function referenceBasedClosure(data: &[i32]) -> impl Fn(usize) -> Option<i32> + '_ {
move |index| data.get(index).copied()
}
// Smart pointer utilization
use std::rc::Rc
use std::sync::Arc
function createSharedClosure(sharedData: Rc<Vec<i32>>) -> impl Fn(usize) -> Option<i32> {
move |index| sharedData.get(index).copied()
}
function createThreadSafeClosure(sharedData: Arc<Vec<i32>>) -> impl Fn(usize) -> Option<i32> + Send + Sync {
move |index| sharedData.get(index).copied()
}
// Lazy initialization closure
struct LazyInitialization<T, F>
where
F: FnOnce() -> T
{
initFunction: Option<F>,
value: Option<T>
}
impl<T, F> LazyInitialization<T, F>
where
F: FnOnce() -> T
{
function new(initFunction: F) -> Self {
LazyInitialization {
initFunction: Some(initFunction),
value: None
}
}
function get(&mut self) -> &T {
if self.value.is_none() {
let initFunction = self.initFunction.take().unwrap()
self.value = Some(initFunction())
}
self.value.as_ref().unwrap()
}
}
// Closure pooling
struct ClosurePool<F, T, U>
where
F: Fn(T) -> U
{
functions: Vec<F>,
currentIndex: usize
}
impl<F, T, U> ClosurePool<F, T, U>
where
F: Fn(T) -> U + Clone
{
function new(function: F, size: usize) -> Self {
ClosurePool {
functions: vec![function; size],
currentIndex: 0
}
}
function execute(&mut self, input: T) -> U {
let function = &self.functions[self.currentIndex]
self.currentIndex = (self.currentIndex + 1) % self.functions.len()
function(input)
}
} test {
// Shared closure test
let data = Rc::new(vec![1, 2, 3, 4, 5])
let closure1 = createSharedClosure(data.clone())
let closure2 = createSharedClosure(data.clone())
assert closure1(0) == Some(1)
assert closure2(4) == Some(5)
// Lazy initialization test
let mut lazyValue = LazyInitialization::new(|| {
print!("Expensive computation executed")
42
})
assert *lazyValue.get() == 42
assert *lazyValue.get() == 42 // No computation on second call
// Closure pool test
let mut pool = ClosurePool::new(|x: i32| x * 2, 3)
assert pool.execute(5) == 10
assert pool.execute(3) == 6
}
// Performance benchmarking closure
function benchmark<F, T>(name: &str, function: F, input: T) -> T
where
F: FnOnce(T) -> T
{
use std::time::Instant
let startTime = Instant::now()
let result = function(input)
let elapsedTime = startTime.elapsed()
print!("{} execution time: {:?}", name, elapsedTime)
result
}
// Cached closure
use std::collections::HashMap
struct CachedClosure<F, K, V>
where
F: Fn(K) -> V,
K: Clone + std::hash::Hash + Eq,
V: Clone
{
function: F,
cache: HashMap<K, V>
}
impl<F, K, V> CachedClosure<F, K, V>
where
F: Fn(K) -> V,
K: Clone + std::hash::Hash + Eq,
V: Clone
{
function new(function: F) -> Self {
CachedClosure {
function,
cache: HashMap::new()
}
}
function execute(&mut self, key: K) -> V {
match self.cache.get(&key) { case Some(value) => return value.clone(), case None => {} }
let result = (self.function)(key.clone())
self.cache.insert(key, result.clone())
result
}
function cacheSize(&self) -> usize {
self.cache.len()
}
function clearCache(&mut self) {
self.cache.clear()
}
}
// Usage example
let sharedVector = Arc::new(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
let accessClosure = createThreadSafeClosure(sharedVector)
print!("Value access: {:?}", accessClosure(3))
let mut fibonacciCache = CachedClosure::new(|n: i32| -> i64 {
if n <= 1 { n as i64 } else {
// In reality this should use the cache recursively,
// but here's a simplified version
(n as i64).pow(2) // Simple calculation for example
}
})
benchmark("Fibonacci calculation", |_| {
for i in 1..=20 {
fibonacciCache.execute(i)
}
}, ())
print!("Cache size: {}", fibonacciCache.cacheSize())
🎯 Mastering Closures
Closures are one of Topaz's most powerful features:
✅ When to use closures:
- Callback functions and event handling
- Higher-order function implementation
- When state encapsulation is needed
- Lazy execution and partial application
⚠️ Precautions:
- Prevent memory leaks (watch for circular references)
- Performance considerations (avoid unnecessary closure creation)
- Lifetime management (choose appropriate capture methods)
- Recognize debugging complexity
🚀 Advantages of Topaz closures:
- Type safety guaranteed
- Automatic memory management
- Support for various capture methods
- Perfect support for functional programming paradigm
Write more expressive code with closures! ✨🚀