面试题答案
一键面试1. 使用闭包优化矩阵乘法
在Rust中,矩阵乘法常规实现如下:
fn matrix_multiply(a: &[[i32]], b: &[[i32]]) -> Vec<Vec<i32>> {
let rows_a = a.len();
let cols_a = a[0].len();
let cols_b = b[0].len();
let mut result = vec![vec![0; cols_b]; rows_a];
for i in 0..rows_a {
for j in 0..cols_b {
for k in 0..cols_a {
result[i][j] += a[i][k] * b[k][j];
}
}
}
result
}
为了使用闭包优化,我们可以利用闭包的特性来并行化计算。例如,使用rayon
库来并行处理矩阵乘法:
use rayon::prelude::*;
fn matrix_multiply_parallel(a: &[[i32]], b: &[[i32]]) -> Vec<Vec<i32>> {
let rows_a = a.len();
let cols_a = a[0].len();
let cols_b = b[0].len();
let mut result = vec![vec![0; cols_b]; rows_a];
(0..rows_a).into_par_iter().for_each(|i| {
for j in 0..cols_b {
for k in 0..cols_a {
result[i][j] += a[i][k] * b[k][j];
}
}
});
result
}
这里闭包|i| {... }
作为for_each
的参数,使得对每一行的计算可以并行执行,从而在处理大规模矩阵时提高性能。
2. 闭包管理状态和提高复用性
- 管理状态:闭包可以捕获其定义环境中的变量,从而管理状态。例如,在上述并行矩阵乘法中,闭包
|i| {... }
捕获了a
、b
和result
,并在其内部使用这些变量进行计算。闭包在不同的并行线程中执行,但通过捕获的变量,它们都能正确访问和修改所需的数据。 - 提高复用性:闭包可以作为参数传递给不同的函数,从而提高代码的复用性。例如,我们可以定义一个通用的矩阵操作函数,接受一个闭包来定义具体的操作:
fn matrix_operation(a: &[[i32]], b: &[[i32]], op: impl FnMut(i32, i32) -> i32) -> Vec<Vec<i32>> {
let rows_a = a.len();
let cols_a = a[0].len();
let cols_b = b[0].len();
let mut result = vec![vec![0; cols_b]; rows_a];
for i in 0..rows_a {
for j in 0..cols_b {
for k in 0..cols_a {
result[i][j] += op(a[i][k], b[k][j]);
}
}
}
result
}
// 使用示例
let add = |x, y| x + y;
let multiply = |x, y| x * y;
let a = vec![vec![1, 2], vec![3, 4]];
let b = vec![vec![5, 6], vec![7, 8]];
let sum_result = matrix_operation(&a, &b, add);
let product_result = matrix_operation(&a, &b, multiply);
3. 通过闭包减少不必要的内存分配
闭包可以减少不必要的内存分配主要通过以下方式:
- 复用现有数据结构:闭包可以直接操作传入的参数,而不需要创建大量临时的数据结构。例如在矩阵乘法中,闭包直接对输入矩阵
a
和b
进行操作,并将结果累加到result
中,而不是在每次计算时创建新的矩阵。 - 延迟计算:闭包可以实现延迟计算,只有在真正需要结果时才进行计算和内存分配。例如,我们可以定义一个闭包来生成矩阵的计算结果,但不立即分配内存:
fn lazy_matrix_operation(a: &[[i32]], b: &[[i32]], op: impl FnMut(i32, i32) -> i32) -> impl Fn() -> Vec<Vec<i32>> {
let rows_a = a.len();
let cols_a = a[0].len();
let cols_b = b[0].len();
move || {
let mut result = vec![vec![0; cols_b]; rows_a];
for i in 0..rows_a {
for j in 0..cols_b {
for k in 0..cols_a {
result[i][j] += op(a[i][k], b[k][j]);
}
}
}
result
}
}
// 使用示例
let lazy_add = lazy_matrix_operation(&a, &b, |x, y| x + y);
// 此时还未分配内存
let sum_result = lazy_add();
// 调用闭包时才分配内存
通过这种方式,我们可以在需要时才进行内存分配,避免了在程序初始化阶段就分配大量内存的情况。