我想要一个返回多种类型的Range的函数(例如RangeRangeFromRangeTo)。我的目标是检查值是在编译时我们不知道的范围内(无论它们是打开还是关闭)。

我试图通过指定RangeBounds的返回类型来做到这一点。不幸的是,因为.contains是通用的,所以我认为这是不可能的。

还有另一种方法吗?还是我应该只传递(Option<isize>, Option<isize>),并手动检查它们的值?

这个问题比解释这个具体错误更广泛-我正在尝试寻找是否还有另一种方法可以实现目标。我想使用标准库Range工具,而不是自定义实现。

use std::ops::{Range, RangeBounds};

fn range(start: Option<isize>, end: Option<isize>) -> dyn RangeBounds<isize> {
    match (start, end) {
        (Some(s), Some(e)) => Range { s, e },
        // other options here
        _ => panic!(),
    }
}

原因:

error[E0038]: the trait `std::ops::RangeBounds` cannot be made into an object
 --> src/lib.rs:3:1
  |
3 | fn range(start: Option<isize>, end: Option<isize>) -> dyn RangeBounds<isize> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::RangeBounds` cannot be made into an object
  |
  = note: method `contains` has generic type parameters

另一种无效的方法:

use std::ops::{Range, RangeBounds, RangeFrom, RangeTo};
fn range(start: Option<isize>, end: Option<isize>) -> impl RangeBounds<isize> {
    match (start, end) {
        (Some(s), Some(e)) => Range { start: s, end: e },
        (Some(s), None) => RangeFrom { start: s },
        // other options here
        _ => panic!(),
    }
}

error[E0308]: match arms have incompatible types
  --> src/main.rs:18:28
   |
16 | /     match (start, end) {
17 | |         (Some(s), Some(e)) => Range { start: s, end: e  },
   | |                               --------------------------- this is found to be of type `std::ops::Range<isize>`
18 | |         (Some(s), None) => RangeFrom { start: s },
   | |                            ^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::ops::Range`, found struct `std::ops::RangeFrom`
19 | |         // other options here
20 | |         _ => panic!(),
21 | |     }
   | |_____- `match` arms have incompatible types

最佳答案

你不知道您不能返回不安全对象特征的特征对象。已经对此进行了详尽的解释:

  • The trait cannot be made into an object
  • Why does a generic method inside a trait require trait object to be sized?
  • What is the cited problem with using generic type parameters in trait objects?

  • 而是定义您自己的对象安全特征,并根据非对象安全特征来实现它:
    use std::ops::{Range, RangeBounds};
    
    trait MyBounds {
        fn contains(&self, v: &isize) -> bool;
    }
    
    impl<T> MyBounds for T
    where
        T: RangeBounds<isize>,
    {
        fn contains(&self, v: &isize) -> bool {
            RangeBounds::contains(self, v)
        }
    }
    
    fn range(start: Option<isize>, end: Option<isize>) -> Box<dyn MyBounds> {
        match (start, end) {
            (Some(start), Some(end)) => Box::new(Range { start, end }),
            // other options here
            _ => panic!(),
        }
    }
    

    也可以看看:
  • Create an Object-safe Trait in Rust with a method that accepts a closure
  • Why can impl trait not be used to return multiple / conditional types?
  • Conditionally iterate over one of several possible iterators
  • How do I return an instance of a trait from a method?
  • 关于rust - 如何返回实现非对象安全特征的多种类型之一?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57277497/

    10-12 18:08