为什么 Vec<T> 期望 &T 作为 binary_search 的参数?

Gre*_*xis 8 rust

这个问题基于这样一个假设,即 rust 中的友好/符合人体工程学的 API 应该更喜欢引用类型QwhereT: Borrow<Q>而不是&T直接期望。根据我使用其他集合类型(如 )的 API 的经验HashMap,情况似乎确实如此。那说...

为什么binary_search方法 onVec<T>不是那样定义的?目前,在稳定上,binary_search实现如下:

pub fn binary_search(&self, x: &T) -> Result<usize, usize>
where
    T: Ord,
{
    self.binary_search_by(|p| p.cmp(x))
}
Run Code Online (Sandbox Code Playgroud)

似乎以下将是一个更好的实现:

pub fn binary_search_modified<Q>(&self, x: &Q) -> Result<usize, usize>
where
    T: Borrow<Q>,
    Q: Ord + ?Sized,
{
    self.binary_search_by(|p| p.borrow().cmp(x))
}
Run Code Online (Sandbox Code Playgroud)

上面两个API的比较:

let mut v: Vec<String> = Vec::new();
v.push("A".into());
v.push("B".into());
v.push("D".into());
let _ = v.binary_search("C"); // Compilation error!
let _ = v.binary_search(&String::from("C")); // Fine allocate and convert it to the exact type, I guess
let _ = v.binary_search_modified("C"); // Far nicer API, does the same thing
let _ = v.binary_search_modified(&String::from("C")); // Backwards compatible
Run Code Online (Sandbox Code Playgroud)

作为一个更一般的问题,决定一个方法是否应该接受&T&Q ... where T: Borrow<Q>

Sve*_*ach 7

你是对的,binary_search()还有一些其他的方法,比如contains()可以被推广以接受任何可以借用的类型T,但不幸的是,Rust 1.0 发布时带有不太通用的签名。虽然看起来 usingBorrow更通用,但在太多情况下尝试实现该更改会破坏类型推断。

关于这个话题有无数的 Github 问题、PR 和论坛讨论。如果您想跟踪解决此问题的尝试历史,我建议从PRbinary_search()开始,最终恢复尝试使更通用并倒退的尝试

关于您更一般的问题,我的建议与任何 API 设计问题相同:考虑用例。使用额外的类型参数会使代码更加复杂,并且文档和编译器错误变得不那么明显。对于 trait 上的方法,类型参数将使 trait 无法用于 trait 对象。因此,如果您可以为更通用的版本 using 想出令人信服的用例Borrow,那就去做吧,但如果没有令人信服的用例,最好避免使用它。