Как я могу использовать объект как параметр его собственного метода в Rust?
Я написал следующий код для простой структуры в Rust. Это всего лишь пример, у него нет реальной логики:
struct Vec2 {
x: f32,
y: f32,
}
impl Vec2 {
fn multiply(&mut self, other: &Vec2) {
self.x *= other.x;
self.y *= other.y;
}
}
Я могу создать простые векторы и умножить вектор на другой вектор, но я столкнулся с проблемой при попытке умножить вектор на себя: компилятор жалуется, что я не могу заимствовать этот вектор как изменяемый, поскольку он также заимствован как неизменяемый.
fn main() {
let mut vec = Vec2 { x: 2.0, y: 2.3 };
vec.multiply(&vec);
}
error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable
--> src/main.rs:15:5
|
15 | vec.multiply(&vec);
| ^^^^--------^----^
| | | |
| | | immutable borrow occurs here
| | immutable borrow later used by call
| mutable borrow occurs here
Это имеет смысл, но как правильно умножить такой вектор на себя? И что еще более важно: для общего случая, когда мне нужно изменить структуру своим собственным методом с той же самой структурой, что и параметр.
1 ответ
Я думаю, что вы уже понимаете это, но причина того, что у вас сейчас не работает, состоит в том, что стоимость не может быть заимствована в одно и то же время, что и неизменный заем. Чтобы выполнить метод как есть, вам потребуется как изменяемый заем (в форме &mut self
) и неизменный заем (в форме other: &Vec2
) в то же время. Поскольку ваш метод должен работать для любых двух членов Vec2
у вас всегда будет два отдельных заимствования: компилятор не может сделать вывод, что один заем будет работать в случае умножения вектора на себя.
Что касается вашего вопроса, у вас есть несколько вариантов, в зависимости от деталей того, что вы пытаетесь сделать.
Вариант 1: клонирование
Просто добавь #[derive(Clone)]
к вашему определению Vec2
и вы сможете клонировать элемент этого типа, используя clone
метод.
#[derive(Clone)]
struct Vec2 {
x: f32,
y: f32,
}
impl Vec2 {
fn multiply(&mut self, other: &Vec2) {
self.x *= other.x;
self.y *= other.y;
}
}
fn main() {
let mut vec = Vec2 { x: 2.0, y: 2.3 };
vec.multiply(&vec.clone());
}
Вариант 2: копирование
Если ваш тип такой простой (всего два числа с плавающей запятой), то вы также можете получить Copy
, Затем элементы типа просто копируются при подаче в функции, а не в ссылке. Это означает, что мы должны изменить подпись Vec2::multiply
принять other
так же просто Vec2
, скорее, чем &Vec2
(это не является строго необходимым, но использование указателя обычно менее эффективно для Copy
типов).
#[derive(Copy, Clone)]
struct Vec2 {
x: f32,
y: f32,
}
impl Vec2 {
fn multiply(&mut self, other: Vec2) {
self.x *= other.x;
self.y *= other.y;
}
}
fn main() {
let mut vec = Vec2 { x: 2.0, y: 2.3 };
vec.multiply(vec);
}
Вариант 3: выделенный метод
Вы могли бы иметь отдельный метод с именем multiply_self
или же square
(в зависимости от вашей семантики), который просто занимает &mut self
, Это может быть вашим лучшим выбором в общем случае изменения структуры с использованием самой себя.
struct Vec2 {
x: f32,
y: f32,
}
impl Vec2 {
fn multiply_self(&mut self) {
self.x *= self.x;
self.y *= self.y;
}
}
fn main() {
let mut vec = Vec2 { x: 2.0, y: 2.3 };
vec.multiply_self();
}
Вариант 4: вернуть новое значение
Вы могли бы иметь метод, который не берет self
изменчиво и вместо этого возвращает новый Vec2
, Тогда вы могли бы сделать vec = vec.multiply(&vec)
,
struct Vec2 {
x: f32,
y: f32,
}
impl Vec2 {
fn multiply(&self, other: &Vec2) -> Vec2 {
Vec2 {
x: self.x * other.x,
y: self.y * other.y,
}
}
}
fn main() {
let mut vec = Vec2 { x: 2.0, y: 2.3 };
vec = vec.multiply(&vec)
}
Вероятно, есть много других способов сделать это, но это то, что приходит на ум в этом простом случае. Если вы поделитесь более подробной информацией о том, что вы пытаетесь сделать в целом, я мог бы предложить больше.