[英]How is synchronizing is a problem for multiple mutable references in Rust?
[英]How to prevent destruction of references to local variables in Rust?
我有两个结构。 首先是带有两个i32
坐标的Point
,第二个是带有两个Point
引用的Line
。 结构有new
和random
的构造函数。
要求的用法是:
use sandbox::{Point, Line};
fn main() {
let line = Line::new(&Point::new(1, 2),
&Point::new(1, 2));
line.from; // error[E0716]: temporary value dropped while borrowed
Line::random(10, 10); // error[E0515]: cannot return value referencing local variable `a`
}
和结构:
use rand::Rng;
pub struct Point {
pub x: i32,
pub y: i32,
}
pub struct Line<'line> {
pub from: &'line Point,
pub to: &'line Point,
}
impl Point {
pub fn new(x: i32, y: i32) -> Point {
Point { x, y }
}
pub fn random(x_max: i32, y_max: i32) -> Point {
let x = rand::thread_rng().gen_range(0..=x_max);
let y = rand::thread_rng().gen_range(0..=y_max);
return Point::new(x, y);
}
}
impl<'line> Line<'line> {
pub fn new<'a>(from: &'a Point, to: &'a Point) -> Line<'a> {
Line { from, to }
}
pub fn random<'a>(img_width: i32, img_height: i32) -> Line<'a> {
let a = Point::random(img_width, img_height);
let b = Point::random(img_width, img_height);
Line::new(&a, &b)
// error[E0515]: cannot return value referencing local variable `a`
// returns a value referencing data owned by the current function
}
}
出现两个错误。 第一个与传递给Line
的Point::new
在Line::new
执行后被销毁有关,因此无法进一步使用。 可以将其取出到单独的变量中,但这不符合使用要求。
第二个错误与构建Line::random
Point::random
random 是本地的有关,这意味着Line::random
执行后也无法访问。
一种可能的解决方案是使用堆( Box<T>
),但我无法弄清楚如何在函数完成后避免破坏。
我认为您对引用的使用在这里放错了地方。
如果Line
必须有引用,我会改用引用计数的智能指针。
主要问题是,如果您将引用存储在Line
中, Line
不拥有Point
s。 这意味着,你必须让它们在外部保持活力。
这就是random
构造函数失败的原因:
pub fn random(x_max: i32, y_max: i32) -> Point {
let x = rand::thread_rng().gen_range(0..=x_max);
let y = rand::thread_rng().gen_range(0..=y_max);
return Point::new(x, y);
}
由于Point::new
不拥有x
和y
的所有权,因此变量x
和y
在random
函数的末尾不再存在。
有两种方法可以解决这个问题:
Point
可克隆)在您的情况下,由于Point
是一种非常微不足道的类型,我会选择第一个选项:
use sandbox::{Line, Point};
fn main() {
let line = Line::new(Point::new(1, 2), Point::new(1, 2));
println!("{:?}", line);
let line2 = Line::random(10, 10);
println!("{:?}", line2);
}
use rand::Rng;
#[derive(Clone, Debug)]
pub struct Point {
pub x: i32,
pub y: i32,
}
#[derive(Clone, Debug)]
pub struct Line {
pub from: Point,
pub to: Point,
}
impl Point {
pub fn new(x: i32, y: i32) -> Point {
Point { x, y }
}
pub fn random(x_max: i32, y_max: i32) -> Point {
let x = rand::thread_rng().gen_range(0..=x_max);
let y = rand::thread_rng().gen_range(0..=y_max);
return Point::new(x, y);
}
}
impl Line {
pub fn new(from: Point, to: Point) -> Line {
Line { from, to }
}
pub fn random(img_width: i32, img_height: i32) -> Line {
let a = Point::random(img_width, img_height);
let b = Point::random(img_width, img_height);
Line::new(a, b)
}
}
输出:
Line { from: Point { x: 1, y: 2 }, to: Point { x: 1, y: 2 } }
Line { from: Point { x: 9, y: 1 }, to: Point { x: 9, y: 1 } }
此解决方案仅供参考。
如前所述,这对于简单的数据结构来说太过分了,它应该派生出Clone
特征。
如果您处于多线程环境中,请将Rc<RefCell<Point>>
替换为Arc<Mutex<Point>>
。
use std::{cell::RefCell, rc::Rc};
use sandbox::{Line, Point};
fn main() {
let line = Line::new(
Rc::new(RefCell::new(Point::new(1, 2))),
Rc::new(RefCell::new(Point::new(1, 2))),
);
println!("{:?}", line);
let line2 = Line::random(10, 10);
println!("{:?}", line2);
}
use std::{cell::RefCell, rc::Rc};
use rand::Rng;
#[derive(Debug)]
pub struct Point {
pub x: i32,
pub y: i32,
}
#[derive(Debug)]
pub struct Line {
pub from: Rc<RefCell<Point>>,
pub to: Rc<RefCell<Point>>,
}
impl Point {
pub fn new(x: i32, y: i32) -> Point {
Point { x, y }
}
pub fn random(x_max: i32, y_max: i32) -> Point {
let x = rand::thread_rng().gen_range(0..=x_max);
let y = rand::thread_rng().gen_range(0..=y_max);
return Point::new(x, y);
}
}
impl Line {
pub fn new(from: Rc<RefCell<Point>>, to: Rc<RefCell<Point>>) -> Line {
Line { from, to }
}
pub fn random(img_width: i32, img_height: i32) -> Line {
let a = Rc::new(RefCell::new(Point::random(img_width, img_height)));
let b = Rc::new(RefCell::new(Point::random(img_width, img_height)));
Line::new(a, b)
}
}
输出:
Line { from: RefCell { value: Point { x: 1, y: 2 } }, to: RefCell { value: Point { x: 1, y: 2 } } }
Line { from: RefCell { value: Point { x: 9, y: 1 } }, to: RefCell { value: Point { x: 4, y: 8 } } }
好吧,这看起来像您需要有时引用和有时拥有这些点。 Rust 提供了Cow
在这种情况下派上用场:
use rand::Rng;
use std::borrow::Cow;
#[derive(Clone)]
pub struct Point {
pub x: i32,
pub y: i32,
}
pub struct Line<'line> {
pub from: Cow<'line, Point>,
pub to: Cow<'line, Point>,
}
impl Point {
pub fn new(x: i32, y: i32) -> Point {
Point { x, y }
}
pub fn random(x_max: i32, y_max: i32) -> Point {
let x = rand::thread_rng().gen_range(0..=x_max);
let y = rand::thread_rng().gen_range(0..=y_max);
return Point::new(x, y);
}
}
impl<'line> Line<'line> {
pub fn new(from: &'line Point, to: &'line Point) -> Line<'line> {
Line { from: Cow::Borrowed(from), to: Cow::Borrowed(to)}
}
pub fn random(img_width: i32, img_height: i32) -> Line<'line> {
let a = Point::random(img_width, img_height);
let b = Point::random(img_width, img_height);
Self {
from: Cow::Owned(a),
to: Cow::Owned(b)
}
}
}
一种可能的解决方案是使用堆(Box),但我无法弄清楚在函数完成后如何避免破坏。
并非如此, Box
仍然受制于 rust 借用规则,除非您泄漏它(使引用&'static
),否则会抱怨在函数范围之后丢弃的临时值。
关于main
,您只需要将Point
s 绑定到一个变量,这样它们就会在main
的范围内存在:
fn main() {
let (from, to) = (Point::new(1, 2), Point::new(1, 2));
let line = Line::new(&from, &to);
line.from;
Line::random(10, 10);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.