首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >你能控制借用结构还是借用字段吗?

你能控制借用结构还是借用字段吗?
EN

Stack Overflow用户
提问于 2015-04-27 13:04:47
回答 2查看 604关注 0票数 5

我正在进行一个项目,其中包含一个类似于以下内容的结构:

代码语言:javascript
复制
struct App {
    data: Vec<u8>,
    overlay: Vec<(usize, Vec<u8>)>,
    sink: Sink,
}

简单地说,data字段包含一些字节,而overlay是一系列要在特定索引处插入的字节序列。Sink类型不重要,只是它具有如下函数:

代码语言:javascript
复制
impl Sink {
    fn process<'a>(&mut self, input: Vec<&'a [u8]>) {
        // ...
    }
}

我实现了一个迭代器来合并来自dataoverlay的信息,供Sink使用。

代码语言:javascript
复制
struct MergeIter<'a, 'b> {
    data: &'a Vec<u8>,
    overlay: &'b Vec<(usize, Vec<u8>)>,
    // iterator state etc.
}

impl<'a, 'b> Iterator for MergeIter<'a, 'b> {
    type Item = &'a [u8];
    // ...
}

这是一个小小的谎言,因为迭代器返回的每个&u8的生命周期并不总是原始data的生命周期。从overlay插入的数据具有不同的生命周期,但我不知道如何更准确地注释它。无论如何,借用检查器似乎并不介意--以下方法有效:

代码语言:javascript
复制
fn merge<'a, 'b>(data: &'a Vec<u8>, overlay: &'b Vec<(usize, Vec<u8>)>, start: usize) -> Vec<&'a [u8]> {
    MergeIter::new(data, overlay, start).collect()
}

impl App {
    fn process(&mut self) {
        let merged = merge(&self.data, &self.overlay, 0);
        // inspect contents of 'merged'
        self.sink.process(merged);
    }
}

最后,我在所有地方都使用了这个merge函数,但是总是针对相同的数据/覆盖。因此,为了方便起见,我将添加一个App::merge函数,问题从这里开始:

代码语言:javascript
复制
impl App {
    fn merge<'a>(&'a self, start: usize) -> Vec<&'a [u8]> {
        MergeIter::new(&self.data, &self.overlay, start).collect()
    }

    fn process(&mut self) {
        let merged = self.merge(0);
        // inspect contents of 'merged'
        self.sink.process(merged);
    }
}

App::process现在无法通过借入检查器--它拒绝允许self.sink的可变借用,而self是被借用的。

我与此斗争了一段时间,如果我理解正确的话,问题不是用process,而是用这个签名:

代码语言:javascript
复制
fn merge<'a>(&'a self, start: usize) -> Vec<&'a [u8]> {

在这里,我实际上已经告诉借阅检查器,向量中返回的引用等同于self借阅。

尽管我觉得我现在已经理解了这个问题,但我仍然觉得我的手被束缚了。不使用生存期注释是没有帮助的(因为编译器做的是等效的?),而且只涉及两个引用,我看不出输出引用有一个生命周期绑定到其他东西。

我也试过这个:

代码语言:javascript
复制
fn merge<'a, 'b>(&'b self, start: usize) -> Vec<&'a [u8]> {
    let data: &'a Vec<u8> = &self.data;
    MergeIter::new(&self.data, &self.overlay, start).collect()
}

但是编译器抱怨let语句(“由于需求冲突无法推断出适当的生存期”--我也发现编译器没有解释所述要求令人恼火)。

是否有可能做到这一点?锈蚀引用在生命周期注释和相关语法方面有一定的启发。

每晚(706 be5ba1 2015-02-05 23:14:28 +0000)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-04-27 13:24:48

是的,您已经猜对了--错误的发生是因为当您有merge方法接受&self时,编译器无法在其调用站点上知道它只使用了一些字段-- merge签名只告诉它返回的数据是从self派生的,但它没有说明是如何得到的--所以编译器会出现“最坏”的情况,并阻止您访问self有的其他字段。

恐怕目前没有办法解决这个问题,我也不确定会有什么办法。但是,可以使用宏缩短merge调用:

代码语言:javascript
复制
macro_rules! merge {
    ($this:ident, $start:expr) => {
        MergeIter::new(&$this.data, &$this.overlay, $start).collect()
    }
}

fn process(&mut self) {
    let merged = merge!(self, 0);
    // inspect contents of 'merged'
    self.sink.process(merged);
}
票数 2
EN

Stack Overflow用户

发布于 2015-04-27 13:22:46

只要merge方法采用&self,您就无法实现您想要的结果:它借用了所有的参数,这是不能改变的。

解决方案是修改它,使其不使用self,而是使用您希望借用的各个字段:

代码语言:javascript
复制
impl App {
    ...
    fn merge(data: &Vec<u8>, overlay: &Vec<(usize, Vec<u8>)>, start: usize) -> Vec<&[u8]> {
        MergeIter::new(data, overlay, start).collect()
    }

    fn process(&mut self) {
        let merged = Self::merge(&self.data, &self.overlay, 0);
        ... // inspect contents of 'merged'
        self.sink.process(merged);
    }
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29896672

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档