特征能否保证某些类型属性(例如向量)为非空?

use*_*r89 4 traits rust

想象一下我有这样的功能:

fn min_max_difference(row: &Vec<u32>) -> u32 {
    let mut min_elem: u32 = row[0];
    let mut max_elem: u32 = min_elem;

    for &element in row.iter().skip(1) {
        if element < min_elem {
            min_elem = element;
        } else if element > max_elem {
            max_elem = element;
        }
    }

    result = max_elem - min_elem;
}

fn execute_row_operation(row: &Vec<u32>, operation: Fn(&Vec<u32>) -> u32) -> Option<(u32, u32)> {
    let mut result = None;

    if row.len() > 0 {
        result = operation(row);
    }

    result
}
Run Code Online (Sandbox Code Playgroud)

请注意,if块 inexecute_row_operation保证Vec<u32>传递给operation函数的I是非空的。一般来说,我希望“操作”是接受非空行的函数。如果我能做这样的事情,我会喜欢它:

fn min_max_difference<T: &Vec<u32> + NonEmpty>(row: T) -> u32 {
    //snip
}
Run Code Online (Sandbox Code Playgroud)

这将允许编译器禁止将空向量的引用传递给一个min_max_difference期望这样的函数。

据我所知,traits指定了一个类型有什么方法,而不是一个类型有什么属性。在我的脑海中,我正在想象一个T由带有 type: 的布尔谓词组成的类型Fn<T> -> bool的特征,如果所有这些谓词的计算结果都为真,那么这样的特征就是为一个类型“实现”的。

这样的事情可以实现吗?

She*_*ter 5

特质可以保证某些类型的属性吗

是的,这就是他们的目的。在许多情况下,这些属性是一组函数存在(例如PartialEq::eq)和一组行为存在(例如对称和传递相等,由 要求PartialEq)。

特征也可以没有方法,例如Eq. 这些添加了一组行为(例如自反平等)。这些类型的特征通常被称为标记特征

比如一个向量是非空的?

但是,您并不是在要求您真正想要的东西。您实际上想要一种为类型的某些实现特征的方法。这在 Rust 中是不可能的。

充其量,您可以引入一个newtype。这可能足以满足您的需求,但如果有用,您也可以为该新类型实现自己的标记特征:

struct NonEmptyVec<T>(Vec<T>);

impl<T> NonEmptyVec<T> {
    fn new(v: Vec<T>) -> Result<Self, Vec<T>> {
        if v.is_empty() {
            Err(v)
        } else {
            Ok(NonEmptyVec(v))
        }
    }
}

fn do_a_thing<T>(items: NonEmptyVec<T>) {}

fn main() {
    let mut a = Vec::new();
    // do_a_thing(a); // expected struct `NonEmptyVec`, found struct `std::vec::Vec`
    a.push(42);
    let b = NonEmptyVec::new(a).expect("nope");
    do_a_thing(b);
}
Run Code Online (Sandbox Code Playgroud)
T: &Vec<u32> + NonEmpty
Run Code Online (Sandbox Code Playgroud)

这是无效的,因为它Vec是一种类型并且NonEmpty可能是一个特征——你不能使用类型作为特征边界。


历史记录:

早在很久以前,据我所知,Rust 实际上确实支持您在typestate名称下想要的东西。请参阅什么是类型状态?Typestate是死的,万岁Typestate!.

模拟它的一个例子:

struct MyVec<T, S>
where
    S: VecState,
{
    vec: Vec<T>,
    state: S,
}

trait VecState {}

struct Empty;
struct NonEmpty;

impl VecState for Empty {}
impl VecState for NonEmpty {}

impl<T> MyVec<T, Empty> {
    fn new() -> Self {
        MyVec {
            vec: Vec::new(),
            state: Empty,
        }
    }

    fn push(mut self, value: T) -> MyVec<T, NonEmpty> {
        self.vec.push(value);
        MyVec {
            vec: self.vec,
            state: NonEmpty,
        }
    }
}

fn do_a_thing<T>(items: MyVec<T, NonEmpty>) {}

fn main() {
    let a = MyVec::new();
    // do_a_thing(a); // expected struct `NonEmpty`, found struct `Empty`
    let b = a.push(42);
    do_a_thing(b);
}
Run Code Online (Sandbox Code Playgroud)