如何在 rust 中使用可变引用作为泛型函数的参数

问题描述 投票:0回答:1

我正在尝试练习使用策略模式,并考虑使用运行时选择的函数对向量进行排序,理想情况下能够使用可变引用更改数据。

我尝试在多个位置添加关键字

&mut
,但无法弄清楚如何让我的代码使用可变引用。

这是我的代码

use rand::Rng;

#[derive(Clone)]
pub struct Sorter<F: Fn(Vec<T>) -> Vec<T>, T: Ord + Eq + Copy> {
    sort_strategy: F,
    sort_data: Vec<T>,
}

impl<F: Fn(Vec<T>) -> Vec<T>, T: Ord + Eq + Copy> Sorter<F, T> {
    // return self with sorted data
    // how do i remove the return self and make it a mutable reference to self
    pub fn sort(mut self) -> Self {
        self.sort_data = (self.sort_strategy)(self.sort_data);
        self
    }

    pub fn new(sort_strategy: F, sort_data: Vec<T>) -> Sorter<F, T> {
        Sorter {
            sort_strategy,
            sort_data,
        }
    }
}

// bubble sort function
pub fn bubble_sort<T: Eq + PartialOrd + Copy>(input_vector: Vec<T>) -> Vec<T> {
    let mut output_vector = input_vector.clone();
    for _ in 0..output_vector.len() {
        for j in 0..(output_vector.len() - 1) {
            if output_vector[j] > output_vector[j + 1] {
                output_vector.swap(j + 1, j);
            }
        }
    }
    output_vector
}

// quick sort function
pub fn quick_sort<T: Eq + PartialOrd + Copy>(input_vector: Vec<T>) -> Vec<T> {
    if input_vector.len() <= 1 {
        return input_vector;
    }

    let pivot = rand::thread_rng().gen_range(0..input_vector.len());
    let pivot_val = input_vector[pivot];
    let mut little_vector: Vec<T> = Vec::new();
    let mut big_vector: Vec<T> = Vec::new();

    for i in input_vector.iter().enumerate() {
        if i.0 == pivot {
            continue;
        }
        if *(i.1) > pivot_val {
            big_vector.push(*(i.1));
            continue;
        }
        if *(i.1) <= pivot_val {
            little_vector.push(*(i.1))
        }
    }

    little_vector = quick_sort(little_vector);
    little_vector.push(pivot_val);
    quick_sort(big_vector)
        .iter()
        .for_each(|n| little_vector.push(*n));

    little_vector
}

#[cfg(test)]
mod tests {
    use std::vec;

    use super::*;

    #[test]
    // test that bubble_sort is functional
    fn test_bubble_sort() {
        let data = vec![5, 4, 3, 2, 1];
        let result = bubble_sort(data);
        assert_eq!(result, vec![1, 2, 3, 4, 5])
    }

    #[test]
    // test that quick_sort is functional
    fn test_quick_sort() {
        let data = vec![5, 4, 3, 2, 1];
        let result = quick_sort(data);
        assert_eq!(result, vec![1, 2, 3, 4, 5])
    }

    #[test]
    // test that bubble_sort works in struct Sorter
    fn test_stratergy_pattern_bubble() {
        let sorter = Sorter::new(bubble_sort, vec![5, 4, 3, 2, 1]);
        let sorter = sorter.sort();
        assert_eq!(sorter.sort_data, vec![1, 2, 3, 4, 5]);
    }

    #[test]
    // test that quick_sort works in struct Sorter
    fn test_stratergy_pattern_quick() {
        let sorter = Sorter::new(quick_sort, vec![5, 4, 3, 2, 1]);
        let sorter = sorter.sort();
        assert_eq!(sorter.sort_data, vec![1, 2, 3, 4, 5]);
    }
}

或者 在 Rust 游乐场上

algorithm rust pass-by-reference strategy-pattern
1个回答
0
投票

我想你会希望

Sorter::sort()
看起来像这样:

pub fn sort(&mut self) {
    self.sort_data = (self.sort_strategy)(self.sort_data);
}

...但是抱怨无法脱离参考。原因是您无法获取一个值并将其move

self.sort_strategy
中。这会使
self.sort_data
处于未定义状态,虽然 Rust 有时允许这种部分移动的对象,但分配给
self.sort_data
与此不兼容。

如果你不想改变

sort_data
的签名,那么最简单的方法就是用空向量替换
self.sort_data
,即使用
std::mem::replace(&mut self.sort_data, vec![])
。对于实现
Default
的类型,例如
Vec
,有一个
std::mem::take()
函数可以替换默认值。然后
sort()
看起来像这样:

pub fn sort(&mut self) {
    self.sort_data = (self.sort_strategy)(std::mem::take(&mut self.sort_data));
}

对测试套件进行细微更改后不捕获

sort
的结果,您的测试通过了。 游乐场

© www.soinside.com 2019 - 2024. All rights reserved.