MST
星途 面试题库

面试题:Rust中通过trait对象与函数指针实现复杂代码复用策略

假设有一系列不同类型的图形结构体,如`Circle`、`Rectangle`、`Triangle`等,每个结构体都实现了一个`trait` `Shape`,该`trait`包含一个计算面积的方法`area`。现在需要编写一个函数`total_area`,它接收一个`Shape` trait对象的集合,并计算所有图形的总面积。同时,使用函数指针和闭包来实现一个更灵活的面积计算策略,比如可以对不同类型的图形应用不同的面积计算修正因子,阐述这其中代码复用的关键思路和实现细节。
26.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

使用Rust语言实现如下:

  1. 定义trait和结构体
// 定义Shape trait
trait Shape {
    fn area(&self) -> f64;
}

// 定义Circle结构体
struct Circle {
    radius: f64,
}

impl Shape for Circle {
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }
}

// 定义Rectangle结构体
struct Rectangle {
    width: f64,
    height: f64,
}

impl Shape for Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

// 定义Triangle结构体
struct Triangle {
    base: f64,
    height: f64,
}

impl Shape for Triangle {
    fn area(&self) -> f64 {
        0.5 * self.base * self.height
    }
}
  1. 计算总面积的基本函数
fn total_area(shapes: &[&dyn Shape]) -> f64 {
    shapes.iter().map(|shape| shape.area()).sum()
}
  1. 使用函数指针和闭包实现灵活的面积计算策略
// 定义一个面积修正函数指针类型
type AreaModifier = fn(f64) -> f64;

// 使用函数指针实现灵活计算
fn total_area_with_modifier(shapes: &[&dyn Shape], modifier: AreaModifier) -> f64 {
    shapes.iter().map(|shape| (modifier)(shape.area())).sum()
}

// 使用闭包实现灵活计算
fn total_area_with_closure(shapes: &[&dyn Shape], closure: impl Fn(f64) -> f64) -> f64 {
    shapes.iter().map(|shape| closure(shape.area())).sum()
}

代码复用的关键思路和实现细节:

  1. 关键思路

    • Trait 抽象:通过定义 Shape trait,将不同图形的面积计算方法统一抽象出来。这样,不同的图形结构体只需要实现 Shape trait 中的 area 方法,就可以在统一的接口下进行操作。
    • 函数指针和闭包:它们提供了一种灵活的方式来对面积计算结果进行进一步处理。函数指针和闭包可以作为参数传递给计算总面积的函数,这样在不改变原有图形面积计算逻辑的基础上,能够对不同类型图形的面积应用不同的修正策略。
  2. 实现细节

    • Trait 对象集合total_area 函数接收一个 &[&dyn Shape] 类型的参数,即 Shape trait 对象的切片。这样可以将不同类型但都实现了 Shape trait 的图形对象统一收集起来进行操作。
    • 函数指针:定义了 AreaModifier 类型别名,它是一个函数指针类型,接收一个 f64 类型的面积值,返回一个 f64 类型的修正后面积值。total_area_with_modifier 函数接收这样的函数指针作为参数,并在计算总面积时应用这个函数指针来修正每个图形的面积。
    • 闭包total_area_with_closure 函数接收一个实现了 Fn(f64) -> f64 trait 的闭包作为参数。闭包在灵活性上比函数指针更强,它可以捕获环境变量。在计算总面积时,同样应用闭包来修正每个图形的面积。

在实际使用时,可以这样调用:

fn main() {
    let circle = Circle { radius: 5.0 };
    let rectangle = Rectangle { width: 4.0, height: 3.0 };
    let triangle = Triangle { base: 6.0, height: 4.0 };

    let shapes: Vec<&dyn Shape> = vec![&circle, &rectangle, &triangle];

    let total = total_area(&shapes);
    println!("Total area: {}", total);

    // 使用函数指针
    let modifier: AreaModifier = |area| area * 2.0;
    let total_with_modifier = total_area_with_modifier(&shapes, modifier);
    println!("Total area with modifier: {}", total_with_modifier);

    // 使用闭包
    let total_with_closure = total_area_with_closure(&shapes, |area| area * 3.0);
    println!("Total area with closure: {}", total_with_closure);
}

这段代码实现了对不同类型图形面积的统一计算,并且通过函数指针和闭包实现了灵活的面积修正策略,同时展示了代码复用的关键要点。