这个方法的返回类型是切片还是借用数组?

5

我正在学习Rust编程,具体来说是在8.3小节中的“部门”练习。

我对我创建的一个方法返回的内容有点困惑。

#[derive(Debug, PartialEq, Eq, Hash)]
enum Department {
    Sales,
    Engineering,
}

#[derive(Debug)]
struct Company {
    users: HashMap<Department, Vec<String>>,
}

impl Company {
    fn add_user_to_department(&mut self, department: Department, employee: String) {
        let users = self.users.entry(department).or_insert(Vec::new());
        users.push(employee);
    }

    fn get_users_in_department(&self, department: Department) -> &[String] {
        match self.users.get(&department) {
            Some(u) => &u,
            None => &[]
        }
    }
}

一开始我认为方法 get_users_in_department 返回的是一个 Vec 的切片(或在 None 的情况下是一个静态文字)。

但是,在我的 match 语句中,我没有使用切片语法,而是返回了一个借用的引用指向 Vec

match self.users.get(&department) {
    Some(u) => &u,
    None => &[]
}

如果我要返回一个切片,难道不应该返回 Some(u) => &u[..],

我猜我的困惑在于 get_users_in_department 的返回类型是什么。它是返回一个指向 String 数组的引用,还是一个这个数组的切片。这两种类型可以由于某种强制转换而相互替代吗?如果可以区分这两者,那么何时应该返回其中之一?

1个回答

8

在《Rust参考手册》中有关类型强制转换的说明

类型强制转换是指自动改变值类型的隐式操作。它们只在特定位置自动发生,并且高度限制了哪些类型可以进行强制转换。

下列类型之间允许进行强制转换:

  • 如果 T 实现了 Deref<Target = U>,则允许将 &T&mut T 强制转换为 &U

这种类型强制转换称为deref强制转换。例如,Vec<T> 实现了 Deref<Target = [T]>,因此可以将 &Vec<T> 强制转换为 &[T]

强制转换只能在程序的特定强制转换点发生;这些强制转换点通常是所需类型明确或可以从明确类型推导出来(不需要类型推断)的地方。可能存在的强制转换点包括:

  • 函数结果——在块的最后一行(如果没有以分号结尾)或任何返回语句中的任何表达式。

例如:

// no type coercion
fn vec_to_vec<T>(vec: &Vec<T>) -> &Vec<T> {
    vec
}

// &Vec<T> coerced to &[T] via deref coercion
fn vec_to_slice<T>(vec: &Vec<T>) -> &[T] {
    vec
}

playground

更直接地回答你的问题,get_users_in_department 函数中的 &u 类型是 &Vec<String>,但编译器会为你将其强制转换成 &[String]


在发布的代码中,-> &[String] 明显可见,写上“get_users_in_department 的返回类型是 &Vec<String>”不会有点混淆吗?是否更好地说:“get_users_in_department 的返回类型是 &[String](一个切片引用),因为这是代码中所写的,这是如何实现的?” - Michał Politowski
感谢您的评论,我已经更新了我的答案以使其更加清晰。 - pretzelhammer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接