我能否拥有一个结构体,既可以从切片构建,又可以从拥有的缓冲区构建?

3

我会尽可能清晰地表达。假设我有以下内容:

struct Foo<'a> {
    buffer: &'a [u8],
}

impl<'a> Foo<'a> {
    fn create_builder() -> FooBuilder {
        FooBuilder::new()
    }

    fn from_slice(slice: &[u8]) -> Foo {
        Foo { buffer: slice }
    }
}

struct FooBuilder {
    in_progress_buffer: Vec<u8>,
}

impl FooBuilder {
    fn new() -> FooBuilder {
        FooBuilder { in_progress_buffer: Vec::new() }
    }

    fn push(&mut self, item: u8) {
        self.in_progress_buffer.push(item);
    }

    fn build_foo(self) -> Foo {
        Foo { buffer: self.in_progress_buffer }
    }
}

fn main() {
    // Option1: Gradually construct Foo from FooBuilder
    let mut foo_builder = FooBuilder::new();
    foo_builder.push(7);
    let foo = foo_builder.build_foo();

    // Option2: Construct Foo from a slice
    let v = vec![7];
    let foo2 = Foo::from_slice(&v);
}

这会导致编译错误:

error[E0106]: missing lifetime specifier
  --> src/main.rs:28:27
   |
28 |     fn build_foo(self) -> Foo {
   |                           ^^^ expected lifetime parameter
   |
   = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
   = help: consider giving it a 'static lifetime

这个模式是否可行?我该如何解决编译错误? 由于在 FooBuilder 版本中,FooBuilder 拥有缓冲区,而我不希望强制 Foo 用户在使用 Foo 的整个过程中都要保持 FooBuilder 在作用域内,所以我不确定应该给出什么生命周期说明。


1
乍一看,似乎可以使用CoW。 :) - E net4
为什么Foo不拥有缓冲区? - Boiethios
@Boiethios 我想允许从一个切片反序列化 Foo。Foo 提供了检查切片的方法(例如,缓冲区中有多少项设置为 42),但它从不改变缓冲区。 - Shmoopy
1个回答

2
您可以使用 std::borrow::Cow,正如文档所述:

它可以封装和提供对借用数据的不可变访问,并在需要进行更改或所有权时惰性克隆数据

use std::borrow::Cow;

struct Foo<'a> {
    buffer: Cow<'a, [u8]>,
}

impl<'a> Foo<'a> {
    fn create_builder() -> FooBuilder {
        FooBuilder::new()
    }

    fn from_slice(slice: &[u8]) -> Foo {
        Foo { buffer: slice.into() } // note .into()
    }
}

struct FooBuilder {
    in_progress_buffer: Vec<u8>,
}

impl<'a> FooBuilder {
    fn new() -> FooBuilder {
        FooBuilder { in_progress_buffer: Vec::new() }
    }

    fn push(&mut self, item: u8) {
        self.in_progress_buffer.push(item);
    }

    fn build_foo(self) -> Foo<'a> {
            Foo { buffer: self.in_progress_buffer.into() } // note .into()
    }
}

此外,您需要将 foo_builder 变为可变的,以便能够在其上执行 push 操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接