rust 我如何解决不能为实现我的trait的所有事物定义Ord,也不能使用Ord的trait对象的问题?

kdfy810k  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(150)

我以前tried to implement Ord for all things that implement my trait: you can see my Cookie trait and my Ord implementation.这是不可能的,虽然。我的意图是要求一个名为value的方法,它将key作为字符串返回。对于Ord来说,在排序中使用它。现在我正在努力解决这个问题。需要Ord的部分,我试图将其添加到我的CookieJar中。我希望能够调用itertools.sorted(),这需要这个。

#[derive(Default, Debug)]
pub struct CookieJar {
    _inner: std::collections::HashMap<String, Box<(dyn CookieElement + Ord)>> 
}

这也不起作用,因为Ord不能转换为trait对象。

error[E0225]: only auto traits can be used as additional traits in a trait object
 --> src/cookiejar.rs:7:61
  |
7 |     _inner: std::collections::HashMap<String, Box<dyn Cookie + std::cmp::Ord>> 
  |                                                       ------   ^^^^^^^^^^^^^ additional non-auto trait
  |                                                       |
  |                                                       first non-auto trait
  |
  = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: browser_cookie::Cookie + std::cmp::Ord {}`
  = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>

error[E0038]: the trait `std::cmp::Ord` cannot be made into an object
   --> src/cookiejar.rs:7:48
    |
7   |     _inner: std::collections::HashMap<String, Box<dyn Cookie + std::cmp::Ord>> 
    |                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cmp::Ord` cannot be made into an object
    |
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> /home/ecarroll/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/cmp.rs:293:15
    |
293 | pub trait Eq: PartialEq<Self> {
    |               ^^^^^^^^^^^^^^^ the trait cannot be made into an object because it uses `Self` as a type parameter
...
776 | pub trait Ord: Eq + PartialOrd<Self> {
    |                     ^^^^^^^^^^^^^^^^ the trait cannot be made into an object because it uses `Self` as a type parameter

Some errors have detailed explanations: E0038, E0225.
For more information about an error, try `rustc --explain E0038`.

我不明白这里的描述不容易理解。
我该如何在这里做我想做的事。
我希望能够调用CookieJar.values().sorted()

3pvhb19x

3pvhb19x1#

由于你拥有trait,并且它有一个函数可以让你按键排序,你可以impl Ord for dyn Cookie

use std::cmp::Ordering;
trait Cookie {
    fn name(&self) -> String;
}

impl PartialEq for dyn Cookie {
    fn eq(&self, other: &Self) -> bool {
        self.name().eq(&other.name())
    }
}

impl Eq for dyn Cookie {}

impl PartialOrd for dyn Cookie {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.name().partial_cmp(&other.name())
    }
}

impl Ord for dyn Cookie {
    fn cmp(&self, other: &Self) -> Ordering {
        self.name().cmp(&other.name())
    }
}

这将允许你对Box<dyn Cookie>和其他trait对象的集合进行排序,这些trait对象的derefect为dyn Cookie,并且在它们的集合上使用Itertools::sorted
Playground

szqfcxe2

szqfcxe22#

CookieJar是否需要使用动态分派(Box<dyn Cookie>)?就我个人而言,我会将其参数化:

#[derive(Default, Debug)]
pub struct CookieJar<C: Cookie> {
    _inner: std::collections::HashMap<String, C> 
}

需要CookieJarBox<dyn Cookie>的唯一原因是,如果您在其中存储了实现Cookie的不同类型。
请注意,我在下面完成的示例中对Cookie特性做了一些假设。

pub trait Cookie: std::fmt::Debug {}

impl Cookie for i32 {}

#[derive(Default, Debug)]
pub struct CookieJar<C: Cookie> {
    _inner: std::collections::HashMap<String, C>,
}

pub fn main() {
    let jar = CookieJar {
        _inner: [
            ("cookie1".into(), 5),
            ("cookie2".into(), 12),
            ("cookie3".into(), -2),
            ("cookie4".into(), 2),
        ].into_iter().collect()
    };
    let mut values: Vec<&i32> = jar._inner.values().collect();
    values.sort();
    println!("{:?}", values)
}

Playground
这将打印[-2, 2, 5, 12]
这是因为Ord是为&i32实现的,所以Rust能够对Vec<&i32>进行排序。如果你想把它作为一个泛型函数来返回排序后的值,它看起来应该是这样的:

impl<C: Cookie + Ord> CookieJar<C> {
    fn sorted_values(&self) -> Vec<&C> {
        let mut values: Vec<&C> = self._inner.values().collect();
        values.sort();
        values
    }
}

Playground
请注意,.sorted()在标准Rust中不存在(参见here),除非Deref<HashMap<String, C>CookieJar<C>实现,或者您自己手动实现,否则您无法调用CookieJar.values()
更正(感谢cafce):.sorted()在Rust的标准库中不可用,但它在itertools crate中可用,这可能就是你所说的。我关于泛型的主要观点仍然成立(以及.values()),但请随意调用.sorted()来满足您的需求。

相关问题