相关疑难解决方法(0)

如何制作一个结构体,其中一个字段引用另一个字段

我有以下问题:我有一个从缓冲区解析的数据结构,并包含对这个缓冲区的一些引用,所以解析函数看起来像

fn parse_bar<'a>(buf: &'a [u8]) -> Bar<'a>
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好。但是,为了避免某些生命周期问题,我想将数据结构和底层缓冲区放入一个结构中,如下所示:

struct BarWithBuf<'a> {bar: Bar<'a>, buf: Box<[u8]>}
// not even sure if these lifetime annotations here make sense,
// but it won't compile unless I add some lifetime to Bar
Run Code Online (Sandbox Code Playgroud)

但是,现在我不知道如何实际构造一个BarWithBuf值。

fn make_bar_with_buf<'a>(buf: Box<[u8]>) -> BarWithBuf<'a> {
    let my_bar = parse_bar(&*buf);
    BarWithBuf {buf: buf, bar: my_bar}
}
Run Code Online (Sandbox Code Playgroud)

不起作用,因为buf在 BarWithBuf 值的构造中移动了,但我们借用了它进行解析。

我觉得应该可以做一些类似的事情

fn make_bar_with_buf<'a>(buf: Box<[u8]>) -> BarWithBuf<'a> {

    let mut bwb = BarWithBuf {buf: buf};
    bwb.bar = parse_bar(&*bwb.buf);
    bwb
} …
Run Code Online (Sandbox Code Playgroud)

rust

10
推荐指数
1
解决办法
2829
查看次数

如何在数据结构中使用 BufReader 和 BufWriter 存储 TcpStream

我想要a和 aTcpStream共享,我找到了一个解决方案:如果 BufReader 拥有流的所有权,我如何在其上读取和写入行?BufReaderBufWriter

现在我希望它有自己的数据结构,但我只得到了部分答案:
为什么我不能在同一结构中存储一个值和对该值的引用?

期望的实现违反了所有权规则。

use std::io::{BufReader, BufWriter};
use std::net::TcpStream;

pub struct BufTcpStream<'a> {
    _socket: TcpStream,
    input:  BufReader<&'a TcpStream>;
    output: BufWriter<&'a TcpStream>;
}

impl<'a> BufTcpStream<'a> {
    pub fn new(socket: TcpStream) -> Self {
        Self{
            input : BufReader::new(&socket),
            output: BufWriter::new(&socket),
            _socket: socket,//                 <-- MOVE OF BORROWED VALUE HERE
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我必须确保TcpStream引用在整个结构生命周期内保持有效,我使用了 aPin<Box<TcpStream>>来确保它。

但编译器仍然抱怨借用值的移动socket。为了消除这个障碍,我使用了std::meme::transmute().

现在,我想知道的是:

这个实现安全吗?

use std::io::{BufReader, BufWriter};
use std::net::TcpStream;
use std::pin::Pin;

pub struct BufTcpStream<'a> …
Run Code Online (Sandbox Code Playgroud)

rust

10
推荐指数
1
解决办法
6663
查看次数

如何将 Chars 迭代器存储在与它正在迭代的 String 相同的结构中?

我刚刚开始学习 Rust,我正在努力处理生命周期。

我想要一个带有 a 的结构String,它将用于缓冲来自 stdin 的行。然后我想在结构上有一个方法,它从缓冲区返回下一个字符,或者如果该行中的所有字符都已被消耗,它将从标准输入读取下一行。

文档说 Rust 字符串不能按字符索引,因为 UTF-8 效率低下。当我按顺序访​​问字符时,使用迭代器应该没问题。但是,据我所知,Rust 中的迭代器与它们正在迭代的事物的生命周期相关联,我无法弄清楚如何将这个迭代器与String.

这是我想要实现的伪 Rust。显然它不会编译。

struct CharGetter {
    /* Buffer containing one line of input at a time */
    input_buf: String,
    /* The position within input_buf of the next character to
     * return. This needs a lifetime parameter. */
    input_pos: std::str::Chars
}

impl CharGetter {
    fn next(&mut self) -> Result<char, io::Error> {
        loop {
            match self.input_pos.next() {
                /* If there is still a character left in …
Run Code Online (Sandbox Code Playgroud)

rust

9
推荐指数
1
解决办法
2428
查看次数

不能在一个代码中一次多次借用可变性 - 但可以在另一个代码中非常相似

我的这个片段没有通过借阅检查器:

use std::collections::HashMap;

enum Error {
    FunctionNotFound,
}

#[derive(Copy, Clone)]
struct Function<'a> {
    name: &'a str,
    code: &'a [u32],
}

struct Context<'a> {
    program: HashMap<&'a str, Function<'a>>,
    call_stack: Vec<Function<'a>>,
}

impl<'a> Context<'a> {
    fn get_function(&'a mut self, fun_name: &'a str) -> Result<Function<'a>, Error> {
        self.program
            .get(fun_name)
            .map(|f| *f)
            .ok_or(Error::FunctionNotFound)
    }

    fn call(&'a mut self, fun_name: &'a str) -> Result<(), Error> {
        let fun = try!(self.get_function(fun_name));

        self.call_stack.push(fun);

        Ok(())
    }
}

fn main() {}
Run Code Online (Sandbox Code Playgroud)
error[E0499]: cannot borrow `self.call_stack` as mutable more than …
Run Code Online (Sandbox Code Playgroud)

rust

8
推荐指数
2
解决办法
2258
查看次数

如何在Rust的同一个结构中存储rusqlite Connection和Statement对象?

我正在研究我的第一个Rust程序,并且与Rust所有权语义相冲突.我声明了一个struct将封装SQLite数据库连接,以便它维护一个Connection成员.出于性能原因,我还想保留一个准备好的语句,由Statement类型表示.这是我的代码的简化版本:

extern crate rusqlite; // 0.14.0

use rusqlite::{Connection, Statement};

pub struct Foo<'a> {
    conn: Connection,
    statement: Statement<'a>,
}

impl<'a> Foo<'a> {
    pub fn new() -> Foo<'a> {
        let conn = Connection::open(&":memory:").unwrap();
        let statement = conn
            .prepare("INSERT INTO Foo(name, hash) VALUES($1, $2)")
            .unwrap();
        Foo { conn, statement }
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图通过将conn变量的所有权存储在成员中来将变量的所有权转移给被调用者Foo,但是当我尝试编译此代码时,它失败了:

error[E0597]: `conn` does not live long enough
  --> src/main.rs:13:25
   |
13 |         let statement = conn
   |                         ^^^^ borrowed value …
Run Code Online (Sandbox Code Playgroud)

rust

8
推荐指数
1
解决办法
720
查看次数

如何在不烦扰借用检查器的情况下建模双向地图?

为什么我不能在同一个结构中存储值和对该值的引用?我了解到我无法在同一个结构中存储值和引用.

建议的解决方案是:

最简单和最推荐的解决方案是不要试图将这些项目放在同一个结构中.通过这样做,您的结构嵌套将模仿代码的生命周期.将拥有数据的类型放在一起放在一个结构中,然后提供允许您根据需要获取包含引用的引用或对象的方法.

但是,我不知道如何在我的具体案例中应用这个:

我想构建双向映射,由两个内部实现HashMap.显然,其中一个人必须拥有这些数据.但是,另一部分对双向映射也很重要,所以我看不出如何在保持双向映射接口的同时将这两者分开.

struct BidiMap<'a, S: 'a, T: 'a> { ? }
fn put(&mut self, s: S, t: T) -> ()
fn get(&self, s: &S) -> T
fn get_reverse(&self, t: &T) -> S
Run Code Online (Sandbox Code Playgroud)

lifetime rust borrow-checker

8
推荐指数
1
解决办法
1016
查看次数

处理由C FFI强制执行的有问题的父子关系

我有一个C库,其接口类似于:(我已经在Rust中代表了C API,因此这个问题中的所有代码都可以在一个.rs文件中连接并轻松测试)

// Opaque handles to C structs
struct c_A {}
struct c_B {}

// These 2 `create` functions allocate some heap memory and other 
// resources, so I have represented this using Boxes.
extern "C" fn create_a() -> *mut c_A {
    let a = Box::new(c_A {});
    Box::into_raw(a)
}

// This C FFI function frees some memory and other resources, 
// so I have emulated that here.
extern "C" fn destroy_a(a: *mut c_A) {
    let _a: Box<c_A> = …
Run Code Online (Sandbox Code Playgroud)

ffi lifetime rust

8
推荐指数
1
解决办法
89
查看次数

Rust 中自引用结构的替代方案?

这里有很多关于 Rust 中的自引用结构的问题,我想我已经阅读了所有这些问题,但我仍然无法理解这些问题。在 Rust 中处理自引用结构有哪些设计模式?我会列出我的想法,以便其他人可以告诉我哪里出错了(我有一种感觉,它是在开始时)。

当我学习一门新语言时,我尝试实现相同的游戏,而对于 Rust,我遇到了这个问题:我们有资源,其中一些可以从其他资源中制作。(假设它们形成一个 DAG。)

我对它进行建模的天真尝试是这样的:

struct Resource {
  name: String,
  production_cost: HashMap<&Resource, i32>,
  // other data
}
Run Code Online (Sandbox Code Playgroud)

我们需要一个引用的生命周期注解,所以它变成Resource<'a>了一个HashMap<&'a Resource, i32>.

Vec<Resource>这种形式的A是不切实际的(不可能?)构建,所以另一个尝试是上升一个级别:

struct Resource {
  name: String,
  // other data
}

struct ResourceConfig {
  resources: Vec<Resource>,
  resource_costs: HashMap<&Resource, HashMap<&Resource, i32>>,
}
Run Code Online (Sandbox Code Playgroud)

我也想不出构造其中一个的方法。我能想到的接下来的两个选项是:

  1. 将所有内容都包裹在 RefCell/Rc(或 Arc/Mutex)中。这似乎需要太多的输入,更不用说引用计数的性能开销(我确信这对我来说是微不足道的)。
  2. 将索引传递给主向量。

所以最终结果(2)看起来像:

type RIndex = usize;
type ResourceSet = HashMap<RIndex, i32>;

struct Resource {
  name: String,
  // other data
}

struct ResourceConfig {
  resources: Vec<Resource>,
  resource_costs: HashMap<RIndex, …
Run Code Online (Sandbox Code Playgroud)

rust

8
推荐指数
1
解决办法
3422
查看次数

返回依赖于函数内分配的数据的延迟迭代器

我是Rust的新手并阅读了Rust编程语言,在错误处理部分有一个"案例研究",描述了一个程序,使用csvrustc-serialize库(getopts用于参数解析)从CSV文件中读取数据.

作者编写了一个函数search,该函数使用一个csv::Reader对象逐步执行csv文件的行,并将那些"city"字段与指定值匹配的条目收集到一个向量中并返回它.我采取了与作者略有不同的方法,但这不应该影响我的问题.我的(工作)函数看起来像这样:

extern crate csv;
extern crate rustc_serialize;

use std::path::Path;
use std::fs::File;

fn search<P>(data_path: P, city: &str) -> Vec<DataRow>
    where P: AsRef<Path>
{
    let file = File::open(data_path).expect("Opening file failed!");
    let mut reader = csv::Reader::from_reader(file).has_headers(true);

    reader.decode()
          .map(|row| row.expect("Failed decoding row"))
          .filter(|row: &DataRow| row.city == city)
          .collect()
}
Run Code Online (Sandbox Code Playgroud)

DataRow类型仅仅是一个记录,

#[derive(Debug, RustcDecodable)]
struct DataRow {
    country: String,
    city: String,
    accent_city: String,
    region: String,
    population: Option<u64>, …
Run Code Online (Sandbox Code Playgroud)

iterator allocation heap-memory lifetime rust

7
推荐指数
1
解决办法
342
查看次数

如何在处理数据流时有效地构建向量和该向量的索引?

我有一个结构Foo:

struct Foo {
    v: String,
    // Other data not important for the question
}
Run Code Online (Sandbox Code Playgroud)

我想处理数据流并将结果保存到字段中Vec<Foo>,Vec<Foo>并在字段上为此创建索引Foo::v.

我想使用a HashMap<&str, usize>作为索引,其中键将是&Foo::v,而值是该位置Vec<Foo>,但我对其他建议持开放态度.

我想尽可能快地处理数据流,这需要两次不做明显的事情.

例如,我想:

  • String每个数据流读取只分配一次
  • 不要搜索索引两次,一次检查密钥不存在,一次用于插入新密钥.
  • 不使用Rc或增加运行时间RefCell.

借用检查器不允许此代码:

let mut l = Vec::<Foo>::new();
{
    let mut hash = HashMap::<&str, usize>::new();
    //here is loop in real code, like: 
    //let mut s: String; 
    //while get_s(&mut s) {
    let s = "aaa".to_string();
    let idx: usize = match hash.entry(&s) …
Run Code Online (Sandbox Code Playgroud)

lifetime move-semantics rust borrowing

7
推荐指数
3
解决办法
936
查看次数