Reference 如何将引用升级为可变引用?

Reference 如何将引用升级为可变引用?,reference,rust,Reference,Rust,我有一个围绕一个共享数据结构的程序,建议对数据进行更改,然后在以后的阶段应用这些更改。这些建议的更改保留对核心对象的引用 在C++或其他语言中,我只需使引用非const,然后在需要时进行修改。但Rust不适合这种方法。(今天早些时候,我在IRC上问过这个问题,但遗憾的是,我还是被卡住了。) 为了提供帮助,我制作了一个在剧院订票的精炼示例,其中剧院是数据结构,预订是建议的更改,run方法将应用它们,如果我能够找出如何使其工作的话 首先,定义一些数据结构。剧院有许多排,每排有许多座位: use st

我有一个围绕一个共享数据结构的程序,建议对数据进行更改,然后在以后的阶段应用这些更改。这些建议的更改保留对核心对象的引用

<>在C++或其他语言中,我只需使引用非const,然后在需要时进行修改。但Rust不适合这种方法。(今天早些时候,我在IRC上问过这个问题,但遗憾的是,我还是被卡住了。)

为了提供帮助,我制作了一个在剧院订票的精炼示例,其中剧院是数据结构,预订是建议的更改,
run
方法将应用它们,如果我能够找出如何使其工作的话

首先,定义一些数据结构。剧院有许多排,每排有许多座位:

use std::sync::{Arc, RwLock};
use std::thread;

struct Theatre { rows: Vec<Row> }
struct Row { seats: Vec<Seat> }

struct Seat {
    number: i32,
    booked: bool,
}

impl Seat {
    fn new(number: i32) -> Seat {
        Seat { number: number, booked: false }
    }

    fn book(&mut self) {
        self.booked = true;
    }
}
但这就是我被卡住的地方。
run
方法具有对整个剧场的可变访问权限(通过其参数),并且它知道要改变哪个座位(
self
)。但是由于自我是不可变的,即使包含它的剧场是可变的,它也不能变异

struct Booking<'t> {
    seats: Vec<&'t Seat>
}

impl<'t> Booking<'t> {
    fn describe(&self) {
        let seats: Vec<_> = self.seats.iter().map(|s| s.number).collect();
        println!("You want to book seats: {:?}", seats);
    }

    fn run(&self, _theatre: &mut Theatre) {
        let mut seat = ??????;
        seat.book();
    }
}
令人恼火的是,我确切地知道为什么我当前的代码不能工作——我只是不知道Rust希望我的程序如何格式化。有些事情我不想做:

  • 最简单的解决方案是让
    Booking
    保留其座位的索引,而不是引用:在这种情况下,使用
    座位
    使用字段。然而,虽然我的剧院使用O(1)向量,但我也想引用一棵大树中间的一个值,在那里必须反复寻找价值要昂贵得多。这也意味着,比如说,如果不通过整个剧场,你就无法获得座位号(在
    description
    功能中)
  • 这也可以通过让
    预订
    保存一个对座位的可变引用来解决,我可以像平常一样进行变异。然而,这意味着我一次只能有一个提议的更改:例如,我不能有一个预订列表并同时应用它们,或者有两个预订并只应用一个

我觉得我很快就有了Rust可以接受的东西,但我不知道如何构建我的程序来适应它。有什么建议吗?(双关语)

首先,代码如下:

use std::sync::{Arc, RwLock};
use std::thread;
use std::sync::atomic::{AtomicBool, Ordering};

struct Theatre { rows: Vec<Row> }
struct Row { seats: Vec<Seat> }

struct Seat {
    number: i32,
    booked: AtomicBool,
}

impl Seat {
    fn new(number: i32) -> Seat {
        Seat { number: number, booked: AtomicBool::new(false) }
    }

    fn book(&self) {
        self.booked.store(true, Ordering::Release);
        println!("Booked seat: {:?}", self.number);
    }
}

impl Theatre {
    fn get_booking<'t>(&'t self, number: i32) -> Option<Booking<'t>> {
        for row in self.rows.iter() {
            for seat in row.seats.iter() {
                if seat.number == number && seat.booked.load(Ordering::Acquire) == false {
                    return Some(Booking { seats: vec![ seat ] })
                }
            }
        }

        None
    }
}

struct Booking<'t> {
    seats: Vec<&'t Seat>
}

impl<'t> Booking<'t> {
    fn describe(&self) {
        let seats: Vec<_> = self.seats.iter().map(|s| s.number).collect();
        println!("You want to book seats: {:?}", seats);
    }

    fn run(&self) {
        for seat in self.seats.iter() {
            seat.book();
        }
    }
}

fn main() {
    // Build a theatre (with only one seat... small theatre)
    let theatre = Theatre { rows: vec![ Row { seats: vec![ Seat::new(7) ] } ] };
    let wrapper = Arc::new(RwLock::new(theatre));

    // Try to book a seat in another thread
    let thread = thread::spawn(move || {
        let desired_seat_number = 7;

        let t = wrapper.read().unwrap();
        let booking = t.get_booking(desired_seat_number).expect("No such seat!");

        booking.describe();

        booking.run();
    });

    thread.join().unwrap();
}
使用std::sync::{Arc,RwLock};
使用std::线程;
使用std::sync::atomic::{AtomicBool,Ordering};
结构剧院{rows:Vec}
结构行{seats:Vec}
结构座椅{
编号:i32,
预订:AtomicBool,
}
嵌入式座椅{
fn新(编号:i32)->座椅{
座位{编号:编号,已预订:AtomicBool::new(false)}
}
fn书籍(和自我){
self.booked.store(true,Ordering::Release);
println!(“预订座位:{:?}”,自身编号);
}
}
impl剧院{
fn获取预订选项{

seats:Vec booking非常感谢!这是否意味着在我的数据结构中,我需要将我要更改的所有值包装在互斥锁或rBlock后面?是的。此外,如果使用
Arc
s,您还必须将它们包装在
Arc
中。@BenS:
Mutex
rBlock
如果使用多线程的话g、 否则,
Cell
RefCell
就足够了。
fn main() {
    // Build a theatre (with only one seat... small theatre)
    let theatre = Theatre { rows: vec![ Row { seats: vec![ Seat::new(7) ] } ] };
    let wrapper = Arc::new(RwLock::new(theatre));

    // Try to book a seat in another thread
    let thread = thread::spawn(move || {
        let desired_seat_number = 7;

        let t = wrapper.read().unwrap();
        let booking = t.get_booking(desired_seat_number).expect("No such seat!");

        booking.describe();

        let mut tt = wrapper.write().unwrap();
        booking.run(&mut tt);  // this is never actually reached because we still have the read lock
    });

    thread.join().unwrap();
}
use std::sync::{Arc, RwLock};
use std::thread;
use std::sync::atomic::{AtomicBool, Ordering};

struct Theatre { rows: Vec<Row> }
struct Row { seats: Vec<Seat> }

struct Seat {
    number: i32,
    booked: AtomicBool,
}

impl Seat {
    fn new(number: i32) -> Seat {
        Seat { number: number, booked: AtomicBool::new(false) }
    }

    fn book(&self) {
        self.booked.store(true, Ordering::Release);
        println!("Booked seat: {:?}", self.number);
    }
}

impl Theatre {
    fn get_booking<'t>(&'t self, number: i32) -> Option<Booking<'t>> {
        for row in self.rows.iter() {
            for seat in row.seats.iter() {
                if seat.number == number && seat.booked.load(Ordering::Acquire) == false {
                    return Some(Booking { seats: vec![ seat ] })
                }
            }
        }

        None
    }
}

struct Booking<'t> {
    seats: Vec<&'t Seat>
}

impl<'t> Booking<'t> {
    fn describe(&self) {
        let seats: Vec<_> = self.seats.iter().map(|s| s.number).collect();
        println!("You want to book seats: {:?}", seats);
    }

    fn run(&self) {
        for seat in self.seats.iter() {
            seat.book();
        }
    }
}

fn main() {
    // Build a theatre (with only one seat... small theatre)
    let theatre = Theatre { rows: vec![ Row { seats: vec![ Seat::new(7) ] } ] };
    let wrapper = Arc::new(RwLock::new(theatre));

    // Try to book a seat in another thread
    let thread = thread::spawn(move || {
        let desired_seat_number = 7;

        let t = wrapper.read().unwrap();
        let booking = t.get_booking(desired_seat_number).expect("No such seat!");

        booking.describe();

        booking.run();
    });

    thread.join().unwrap();
}