我正在尝试创建一个由节点组成的单链表,每个节点都有一个对下一个节点的引用,与该节点相关的数据,这是一个有趣的位,即对列表中随机节点的引用.给定节点的随机节点可以出现在节点本身之前,也可以出现在列表中.随机节点是可选的.这是一个图表:
+---------+ +-------------------+
| v v |
+-+--+ ++--++ +----+ +-+--+
+--->+Data+---->+Data+---->+Data+---->+Data|
+-+--+ +----+ +--+-+ +----+
^ |
+----------------------+
Run Code Online (Sandbox Code Playgroud)
该图演示了一个包含四个节点的列表.第一节点的随机引用指向第二节点.缺少第二个节点的随机引用.第三个节点的随机引用是第一个节点.第四个节点的随机引用指向第二个节点.
该列表需要仅支持添加新节点.添加节点后,只要列表存在,就可以通过删除节点使随机引用失效.
我尝试了什么:
我陷入绝对的开端 - 我无法弄清楚如何设计结构以及如何构建列表.这是我在与编译器进行一段时间的摔跤之后得到的代码:
type NodePtr<'a, T> = Option<Box<Node<'a, T>>>;
pub struct Node<'a, T: 'a> {
data: T,
next: NodePtr<'a, T>,
random: Option<&'a Node<'a, T>>,
}
pub struct List<'a, T: 'a> {
root: NodePtr<'a, T>,
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn construct() {
let mut list:List<i32> = List {root: Some(Box::new(Node {data: 5, next: None, random: None}))}; …Run Code Online (Sandbox Code Playgroud) 我正在建立一个PromptSet可以连续问一系列问题的人.出于测试原因,它允许您传递读写器而不是直接使用stdin和stdout.
因为stdin和stdout是常见的用例,所以我想创建一个默认的"构造函数",允许用户生成一个PromptSet<StdinLock, StdoutLock>不需要任何参数.这是迄今为止的代码:
use std::io::{self, BufRead, StdinLock, StdoutLock, Write};
pub struct PromptSet<R, W>
where
R: BufRead,
W: Write,
{
pub reader: R,
pub writer: W,
}
impl<R, W> PromptSet<R, W>
where
R: BufRead,
W: Write,
{
pub fn new(reader: R, writer: W) -> PromptSet<R, W> {
return PromptSet {
reader: reader,
writer: writer,
};
}
pub fn default<'a>() -> PromptSet<StdinLock<'a>, StdoutLock<'a>> {
let stdin = io::stdin();
let stdout = io::stdout();
return PromptSet {
reader: stdin.lock(),
writer: …Run Code Online (Sandbox Code Playgroud) 这段代码不能编译...
fn main() {
let data = "hi".to_string();
let wrap = &data;
std::thread::spawn(move || println!("{}", wrap));
}
Run Code Online (Sandbox Code Playgroud)
...因为data不存在于生成的线程中:
error[E0597]: `data` does not live long enough
--> src/main.rs:3:16
|
3 | let wrap = &data;
| ^^^^^ borrowed value does not live long enough
4 | std::thread::spawn(move || println!("{}", wrap));
| ------------------------------------------------ argument requires that `data` is borrowed for `'static`
5 | }
| - `data` dropped here while still borrowed
Run Code Online (Sandbox Code Playgroud)
为什么 Rustdata不像它那样移动wrap?有什么办法可以强制data一起移动 …
所以我读过为什么我不能在同一结构中存储值和对该值的引用?我明白为什么我的天真方法不起作用,但我仍然很不清楚如何更好地处理我的情况。
我有一个程序,我想构造如下(省略细节,因为无论如何我都无法编译它):
use std::sync::Mutex;
struct Species{
index : usize,
population : Mutex<usize>
}
struct Simulation<'a>{
species : Vec<Species>,
grid : Vec<&'a Species>
}
impl<'a> Simulation<'a>{
pub fn new() -> Self {...} //I don't think there's any way to implement this
pub fn run(&self) {...}
}
Run Code Online (Sandbox Code Playgroud)
我的想法是,我创建一个向量Species(在 的生命周期内不会改变Simulation,除非在特定的互斥锁保护字段中),然后创建一个代表哪个物种生活在哪里的网格,它将自由改变。这个实现是行不通的,至少我想不出任何办法。据我了解,问题在于,无论我如何使用我的new方法,当它返回时,中的所有引用grid都会变得无效,因为Simulation,因此Simulation.species会被移动到堆栈中的另一个位置。即使我可以向编译器证明species及其内容将继续存在,它们实际上不会位于同一个位置。正确的?
我研究了解决这个问题的各种方法,例如在堆上制作或species使用Arcusize而不是引用,以及在物种向量中实现我自己的查找函数,但这些看起来更慢、更混乱或更糟糕。我开始思考的是,我需要真正重新构建我的代码,使其看起来像这样(详细信息用占位符填充,因为现在它实际运行):
use std::sync::Mutex;
struct Species{
index : usize,
population : Mutex<usize>
} …Run Code Online (Sandbox Code Playgroud) 下面是一段更复杂的代码片段,其思想是加载一个 SQL 表并设置一个哈希图,其中一个表结构字段作为键,并将结构保留为值(实现细节并不重要,因为代码工作正常但是,如果我克隆String,数据库中的字符串可以是任意长,并且克隆可能会很昂贵)。
以下代码将失败并显示
error[E0382]: use of partially moved value: `foo`
--> src/main.rs:24:35
|
24 | foo_hashmap.insert(foo.a, foo);
| ----- ^^^ value used here after partial move
| |
| value partially moved here
|
= note: partial move occurs because `foo.a` has type `String`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0382`.
Run Code Online (Sandbox Code Playgroud)
error[E0382]: use of partially moved value: `foo`
--> src/main.rs:24:35
|
24 | foo_hashmap.insert(foo.a, foo);
| ----- …Run Code Online (Sandbox Code Playgroud) 我正在写一个应该从实现BufRead特性的东西中读取的库; 网络数据流,标准输入等.第一个函数应该从该读取器读取数据单元并返回一个填充的结构,该结构主要填充有&'a str从线路中的帧解析的值.
这是一个最小版本:
mod mymod {
use std::io::prelude::*;
use std::io;
pub fn parse_frame<'a, T>(mut reader: T)
where
T: BufRead,
{
for line in reader.by_ref().lines() {
let line = line.expect("reading header line");
if line.len() == 0 {
// got empty line; done with header
break;
}
// split line
let splitted = line.splitn(2, ':');
let line_parts: Vec<&'a str> = splitted.collect();
println!("{} has value {}", line_parts[0], line_parts[1]);
}
// more reads down here, therefore the reader.by_ref() above …Run Code Online (Sandbox Code Playgroud) 我读到 Rust 中的内存默认分配在堆栈上,除非通过使用 aBox或其他方法明确告诉编译器使用堆。
我知道所有权在函数调用之间移动,但实际分配的结构内存在哪里?如果它在堆栈上,当函数退出时会发生什么?
#[derive(Debug)]
struct Foo(i32);
#[derive(Debug)]
struct Bar(Foo);
fn foo() -> Foo {
Foo(42)
}
fn bar() -> Bar {
let f = foo();
Bar(f)
}
fn main() {
let bar = bar();
println!("{:?}", bar);
}
Run Code Online (Sandbox Code Playgroud)
例如,在第 12 行,Foo在bar()函数的堆栈帧中分配了一个结构体。当bar()退出时,堆栈被退绕和所述存储器被回收。既然struct没有实现Copy,内存就没有被复制,那它去哪儿了呢?
我认为这里有一个我不明白的基本思想。