gpt4 book ai didi

generics - 如何使用闭包抽象数据和操作

转载 作者:行者123 更新时间:2023-12-03 11:45:53 25 4
gpt4 key购买 nike

我正在尝试创建在两个方向上从某个源读取数据的代码,而不会重复代码。

use std::iter;

struct Reader {
data: Vec<usize>,
data_rev: Vec<usize>,
data_it: Box<dyn Iterator<Item = usize>>,
data_it_rev: Box<dyn Iterator<Item = usize>>,
}

enum Direction { Forward, Backward }

impl Reader {

fn read(&mut self, n: usize, direction: Direction) {
let (it, adder) = match direction {
Direction::Forward => {
let adder: Box<dyn FnMut(usize) -> ()> = Box::new(|idx| self.data.push(idx));
(&self.data_it, adder)
}
Direction::Backward => {
let adder: Box<dyn FnMut(usize) -> ()> = Box::new(|idx| self.data_rev.insert(0, idx));
(&self.data_it_rev, adder)
}
};
for idx in it.by_ref().take(n) {
adder(idx);
}
}
}

完整代码为 here

在此示例中,我试图表示的是 read 函数,该函数具有公共(public)代码和一些随 read 应该发生的方向而变化的代码。
很明显如何在方向上使用多个模式匹配来编写这个,但我想这样做而不重复自己。

如果可能的话,我想给方向一些通用参数,并有类似的东西

struct Reader<D: Directon> {
data: Vec<usize>,
data_it: Box<Iterator<Item = usize>>
}
trait Reader<Direction> {
fn read(&mut self)
}
// somewhere in code
let reader = match direction {
Direction::Forward => self.forward_reader;
Direction::Backward => self.backward_reader;
}
reader.read()

最佳答案

请注意,将方向放在最终代码中的通用参数中意味着方向是为Reader 的每个实例静态确定的。并且无法更改。如果这是你想要的,你可以通过 Direction 来实现。成为一种特质和ForwardBackward是实现该特征的类型:

trait Direction{}
struct Forward{}
impl Direction for Forward {}
struct Backward{}
impl Direction for Backward {}

struct Reader<D: Direction> {
data: Vec<usize>,
data_it: Box<dyn Iterator<Item = usize>>,
direction: D,
}

impl Reader<Forward> {
fn read (&mut self) { unimplemented!(); }
}

impl Reader<Backward> {
fn read (&mut self) { unimplemented!(); }
}

如果您的 Reader struct 还必须包含一些不依赖于方向的常用函数,您可以将这些函数添加到一个额外的通用 impl堵塞:
impl<T: Direction> Reader<T> {
fn common_function (&self) { unimplemented!(); }
}

由于您希望能够拥有每个实例并在运行时在它们之间切换,因此您需要在 trait 中定义接口(interface),然后使用对该 trait 的引用。此外,为了能够从 trait 实现中访问常用函数,还需要在 super trait 中定义它们:
pub trait Direction{}
pub struct Forward{}
impl Direction for Forward {}
pub struct Backward{}
impl Direction for Backward {}

pub trait CommonReader {
fn common_function (&self);
}

pub trait ReaderItf: CommonReader {
fn read (&mut self);
}

pub struct Reader<D: Direction> {
pub data: Vec<usize>,
pub data_it: Box<dyn Iterator<Item = usize>>,
pub direction: D,
}

impl ReaderItf for Reader<Forward> {
fn read (&mut self) { self.common_function(); }
}

impl ReaderItf for Reader<Backward> {
fn read (&mut self) { unimplemented!(); }
}

impl<T: Direction> CommonReader for Reader<T> {
fn common_function (&self) { unimplemented!(); }
}

// And you use it like this wherever you want to switch at runtime:
pub fn use_reader (r: &mut dyn ReaderItf) {
r.read();
}

Playground

关于generics - 如何使用闭包抽象数据和操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60804382/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com