MST

星途 面试题库

面试题:Rust Option枚举与泛型结合在复杂数据结构中的设计与应用

设计一个Rust的泛型数据结构 `MyContainer`,它内部可能包含一个值,也可能为空,类似于 `Option` 枚举的功能。要求这个数据结构支持类型安全的链式操作,例如类似于 `Option` 的 `map`、`and_then` 方法。并且,当 `MyContainer` 为空时,在调用某些方法(如 `unwrap`)时可以返回一个自定义的错误类型。请详细描述你的设计思路,并给出完整的Rust代码实现。
15.1万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 数据结构定义:定义一个泛型结构体 MyContainer,使用 Option 来存储值,以实现可能为空的特性。
  2. 链式操作方法:实现 mapand_then 方法,使其能够对 MyContainer 中的值进行类型安全的链式操作。
  3. 错误处理:定义一个自定义错误类型,在 unwrap 方法中,当 MyContainer 为空时返回该错误。

Rust代码实现

// 定义自定义错误类型
#[derive(Debug)]
struct MyContainerError {
    message: String,
}

impl std::fmt::Display for MyContainerError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "MyContainer is empty: {}", self.message)
    }
}

impl std::error::Error for MyContainerError {}

// 定义MyContainer泛型结构体
struct MyContainer<T> {
    value: Option<T>,
}

impl<T> MyContainer<T> {
    // 创建一个空的MyContainer
    fn new_empty() -> Self {
        MyContainer { value: None }
    }

    // 创建一个包含值的MyContainer
    fn new(value: T) -> Self {
        MyContainer { value: Some(value) }
    }

    // map方法,对MyContainer中的值进行转换
    fn map<U, F>(self, f: F) -> MyContainer<U>
    where
        F: FnOnce(T) -> U,
    {
        match self.value {
            Some(v) => MyContainer { value: Some(f(v)) },
            None => MyContainer { value: None },
        }
    }

    // and_then方法,对MyContainer中的值进行链式操作
    fn and_then<U, F>(self, f: F) -> MyContainer<U>
    where
        F: FnOnce(T) -> MyContainer<U>,
    {
        match self.value {
            Some(v) => f(v),
            None => MyContainer { value: None },
        }
    }

    // unwrap方法,获取MyContainer中的值,如果为空则返回自定义错误
    fn unwrap(self) -> Result<T, MyContainerError> {
        match self.value {
            Some(v) => Ok(v),
            None => Err(MyContainerError {
                message: "No value present".to_string(),
            }),
        }
    }
}

你可以使用以下方式测试这个代码:

fn main() {
    let result1 = MyContainer::new(5)
      .map(|x| x * 2)
      .and_then(|x| {
            if x > 10 {
                MyContainer::new(x)
            } else {
                MyContainer::new_empty()
            }
        })
      .unwrap();

    match result1 {
        Ok(v) => println!("Result: {}", v),
        Err(e) => eprintln!("Error: {}", e),
    }

    let result2 = MyContainer::new_empty().unwrap();
    match result2 {
        Ok(v) => println!("Result: {}", v),
        Err(e) => eprintln!("Error: {}", e),
    }
}