如何找到无别名的数据结构
How to find an aliasing-free data structure
我正在与 Rust 的最终老板,借用检查器战斗。这是我正在开发的 mio
响应式网络应用程序的简化版本。我花了太多时间为手头的任务寻找正确的数据结构。我想在迭代能够接受新连接的监听套接字时注册一个连接。
查看下面的代码,或者在Rust playground上查看。 HashMap::get_mut
returns self
的 1 个字段中的 1 个值的唯一借用,因此我无法将 self
传递给 Thing::act
。我理解为什么会发生这种情况,如何导致 运行 时间问题,但不知道如何重构数据结构以避免此类问题。
use std::collections::HashMap;
trait ThingSet {
fn register(&mut self, thing: Box<Thing>);
}
trait Thing {
fn act(&mut self, reg: &mut ThingSet);
}
struct Stream;
impl Thing for Stream {
fn act(&mut self, reg: &mut ThingSet) {}
}
struct Listener;
impl Thing for Listener {
fn act(&mut self, reg: &mut ThingSet) {
if true {
let mut stream = Stream {};
reg.register(Box::new(stream));
}
}
}
struct Loop {
next: usize,
things: HashMap<usize, Box<Thing>>,
}
impl Loop {
fn new() -> Loop {
Loop { next: 1, things: HashMap::new(), }
}
fn run(&mut self) {
let mut needs_action = Vec::<&mut Box<Thing>>::new();
{
// modeling a connection on one of the listeners...
if let Some(t) = self.things.get_mut(&1usize) {
needs_action.push(t);
}
}
for t in needs_action {
t.act(self as &mut ThingSet);
}
}
}
impl ThingSet for Loop {
fn register(&mut self, thing: Box<Thing>) {
self.things.insert(self.next, thing);
self.next += 1;
}
}
fn main() {
let mut l = Loop::new();
let mut p1 = Listener {};
let mut p2 = Listener {};
l.register(Box::new(p1));
l.register(Box::new(p2));
l.run();
}
我可以找到很好的教程来解释借用检查器的功能和不允许的功能。我找不到关于如何找到可以避免不允许引用的替代数据结构的好教程。
您能否就如何改造这个具体问题提出建议?
我认为可以纠正这个特定问题,但我觉得这里可能存在更普遍的问题。如果我错了请纠正我,但看起来你 运行 Loop::run
它会扫描你的 ThingSet
然后根据某些条件在 [=] 上放置对 Thing
的可变引用14=]缓冲区。这里的 general 问题似乎是通过不同的迭代,rustc 无法验证这些不同的调用会给你一个不同的可变引用或另一个对同一元素的可变引用。因此,您可以使用 RefCell
之类的东西强制执行 运行 次借用检查(请参阅 Jsor 的回答),或者您可以从 ThingSet
中获取所有权并用某些东西替换您已经拿走的东西else -- 或者从集合中一起删除元素。
例如,获取元素的所有权并将其从 ThingSet
中删除如下所示:
impl Loop {
fn new() -> Loop {
Loop { next: 1, things: HashMap::new(), }
}
fn run(&mut self) {
let mut needs_action = Vec::<Box<Thing>>::new();
// modeling a connection on one of the listeners...
if let Some(t) = self.things.remove(&1usize) {
needs_action.push(t);
}
for t in &mut needs_action {
t.act(self as &mut ThingSet);
}
}
}
我正在与 Rust 的最终老板,借用检查器战斗。这是我正在开发的 mio
响应式网络应用程序的简化版本。我花了太多时间为手头的任务寻找正确的数据结构。我想在迭代能够接受新连接的监听套接字时注册一个连接。
查看下面的代码,或者在Rust playground上查看。 HashMap::get_mut
returns self
的 1 个字段中的 1 个值的唯一借用,因此我无法将 self
传递给 Thing::act
。我理解为什么会发生这种情况,如何导致 运行 时间问题,但不知道如何重构数据结构以避免此类问题。
use std::collections::HashMap;
trait ThingSet {
fn register(&mut self, thing: Box<Thing>);
}
trait Thing {
fn act(&mut self, reg: &mut ThingSet);
}
struct Stream;
impl Thing for Stream {
fn act(&mut self, reg: &mut ThingSet) {}
}
struct Listener;
impl Thing for Listener {
fn act(&mut self, reg: &mut ThingSet) {
if true {
let mut stream = Stream {};
reg.register(Box::new(stream));
}
}
}
struct Loop {
next: usize,
things: HashMap<usize, Box<Thing>>,
}
impl Loop {
fn new() -> Loop {
Loop { next: 1, things: HashMap::new(), }
}
fn run(&mut self) {
let mut needs_action = Vec::<&mut Box<Thing>>::new();
{
// modeling a connection on one of the listeners...
if let Some(t) = self.things.get_mut(&1usize) {
needs_action.push(t);
}
}
for t in needs_action {
t.act(self as &mut ThingSet);
}
}
}
impl ThingSet for Loop {
fn register(&mut self, thing: Box<Thing>) {
self.things.insert(self.next, thing);
self.next += 1;
}
}
fn main() {
let mut l = Loop::new();
let mut p1 = Listener {};
let mut p2 = Listener {};
l.register(Box::new(p1));
l.register(Box::new(p2));
l.run();
}
我可以找到很好的教程来解释借用检查器的功能和不允许的功能。我找不到关于如何找到可以避免不允许引用的替代数据结构的好教程。
您能否就如何改造这个具体问题提出建议?
我认为可以纠正这个特定问题,但我觉得这里可能存在更普遍的问题。如果我错了请纠正我,但看起来你 运行 Loop::run
它会扫描你的 ThingSet
然后根据某些条件在 [=] 上放置对 Thing
的可变引用14=]缓冲区。这里的 general 问题似乎是通过不同的迭代,rustc 无法验证这些不同的调用会给你一个不同的可变引用或另一个对同一元素的可变引用。因此,您可以使用 RefCell
之类的东西强制执行 运行 次借用检查(请参阅 Jsor 的回答),或者您可以从 ThingSet
中获取所有权并用某些东西替换您已经拿走的东西else -- 或者从集合中一起删除元素。
例如,获取元素的所有权并将其从 ThingSet
中删除如下所示:
impl Loop {
fn new() -> Loop {
Loop { next: 1, things: HashMap::new(), }
}
fn run(&mut self) {
let mut needs_action = Vec::<Box<Thing>>::new();
// modeling a connection on one of the listeners...
if let Some(t) = self.things.remove(&1usize) {
needs_action.push(t);
}
for t in &mut needs_action {
t.act(self as &mut ThingSet);
}
}
}