Как я могу передать Вектор внутри для l oop, который проходит через Вектор - PullRequest
1 голос
/ 21 апреля 2020

Мне нужно перебрать изменяемый вектор, и внутри для l oop Мне также нужно передать вектор в функцию, которая изменяет текущий объект.

pub struct Vector2 {
    x: f64,
    y: f64,
}

pub struct Planet {
    position: Vector2,
    init_velocity: Vector2,
    curr_velocity: Vector2,
    radius: f64,
    mass: f64,
}

impl Planet {
    pub fn update_velocity(
        &mut self,
        other_planets: &Vec<Planet>,
        grav_constant: f64,
        timestep: f64,
    ) {
        for p in other_planets {
            // Calculate self's velocity relative to all other planets
        }
    }

    pub fn update_position(&mut self) {
        self.position.x = self.position.x + self.curr_velocity.x;
        self.position.y = self.position.y + self.curr_velocity.y;
    }
}

fn main() {
    let mut planets = Vec::<Planet>::new();
    planets.push(Planet {
        position: Vector2 { x: 10.0, y: 10.0 },
        init_velocity: Vector2 { x: 1.0, y: 1.0 },
        curr_velocity: Vector2 { x: 1.0, y: 1.0 },
        radius: 20.0,
        mass: 500.0,
    });
    for p in &mut planets {
        p.update_velocity(&planets, 0.0000000000674 as f64, 0.0);
        p.update_position();
    }
}
error[E0502]: cannot borrow `planets` as immutable because it is also borrowed as mutable
  --> src/main.rs:42:27
   |
41 |     for p in &mut planets {
   |              ------------
   |              |
   |              mutable borrow occurs here
   |              mutable borrow later used here
42 |         p.update_velocity(&planets, 0.0000000000674 as f64, 0.0);
   |                           ^^^^^^^^ immutable borrow occurs here

Потому что Существует изменчивое заимствование планет, невозможно сделать неизменное или даже другое изменяемое значение, и я не вижу пути обхода этой головоломки.

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

К сожалению, вы не можете легко сделать это, компилятор допускает только один изменяемый заем или несколько заимствований одновременно. Даже если вам кажется, что это должно быть законно с точки зрения ржавчины, это не так.

Существует несколько способов исправить это:

  • использовать индекс напрямую
  • используйте внутреннюю изменчивость
  • есть лучшее решение, которое позволит избежать проблемы

В вашем случае я думаю, что использование индекса имеет смысл, потому что вы не хотите иметь текущие планеты в другом pl anet, поэтому мы можем мутировать вектор, чтобы поместить текущий pl anet в конец и создать подрезок из других планет:

#[derive(Debug)]
pub struct Vector2 {
    x: f64,
    y: f64,
}

#[derive(Debug)]
pub struct Planet {
    position: Vector2,
    init_velocity: Vector2,
    curr_velocity: Vector2,
    radius: f64,
    mass: f64,
}

impl Planet {
    pub fn update_velocity(&mut self, other_planets: &[Planet], grav_constant: f64, timestep: f64) {
        println!("{:#?}", other_planets);
    }

    pub fn update_position(&mut self) {
        self.position.x = self.position.x + self.curr_velocity.x;
        self.position.y = self.position.y + self.curr_velocity.y;
    }
}

struct Guard<'a, T> {
    slice: &'a mut [T],
    a: usize,
    b: usize,
}

impl<'a, T> Guard<'a, T> {
    fn new(slice: &'a mut [T], a: usize, b: usize) -> Self {
        slice.swap(a, b);
        Self { slice, a, b }
    }

    fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
        self.slice.split_last_mut()
    }
}

impl<'a, T> Drop for Guard<'a, T> {
    fn drop(&mut self) {
        self.slice.swap(self.a, self.b);
    }
}

fn main() {
    let mut planets = Vec::<Planet>::new();
    planets.push(Planet {
        position: Vector2 { x: 10.0, y: 10.0 },
        init_velocity: Vector2 { x: 1.0, y: 1.0 },
        curr_velocity: Vector2 { x: 1.0, y: 1.0 },
        radius: 20.0,
        mass: 500.0,
    });
    planets.push(Planet {
        position: Vector2 { x: 20.0, y: 20.0 },
        init_velocity: Vector2 { x: 2.0, y: 2.0 },
        curr_velocity: Vector2 { x: 2.0, y: 2.0 },
        radius: 40.0,
        mass: 1000.0,
    });
    planets.push(Planet {
        position: Vector2 { x: 40.0, y: 40.0 },
        init_velocity: Vector2 { x: 4.0, y: 4.0 },
        curr_velocity: Vector2 { x: 4.0, y: 4.0 },
        radius: 80.0,
        mass: 2000.0,
    });

    let len = planets.len();
    let last = len - 1;
    for i in 0..len {
        let mut g = Guard::new(&mut planets, i, last);

        let (p, other_planets) = g.split_last_mut().unwrap(); // can't fail

        p.update_velocity(&other_planets, 0.0000000000674 as f64, 0.0);
        p.update_position();
    }
}

Playground , Guard существует только для того, чтобы избежать ошибки, ключевой функцией является split_last_mut(), которая разделит наши планеты на ту, которую мы хотим обработать, и остальные.

См .:

0 голосов
/ 22 апреля 2020

Вы можете попробовать использовать индексы для ссылки на конкретный c pl anet без применения правил заимствования. И вам следует избегать разделения ve c планет на две части (действительную и остальные).

pub struct Vector2 {
    x: f64,
    y: f64,
}

pub struct Planet {
    position: Vector2,
    init_velocity: Vector2,
    curr_velocity: Vector2,
    radius: f64,
    mass: f64,
}

impl Planet {
    fn update_velocity_of_all_planets(
        self_idx: usize,
        planets: &mut Vec<Planet>,
        grav_constant: f64,
        timestep: f64,
    ) {
        for p in planets {
            // Do maths stuff with other planets
        }
    }

    pub fn update_position(&mut self) {
        self.position.x = self.position.x + self.curr_velocity.x;
        self.position.y = self.position.y + self.curr_velocity.y;
    }
}

fn main() {
    let mut planets = Vec::<Planet>::new();
    planets.push(Planet {
        position: Vector2 { x: 10.0, y: 10.0 },
        init_velocity: Vector2 { x: 1.0, y: 1.0 },
        curr_velocity: Vector2 { x: 1.0, y: 1.0 },
        radius: 20.0,
        mass: 500.0,
    });
    for idx in 0..planets.len() {
        Planet::update_velocity_of_all_planets(idx, &mut planets, 0.0000000000674 as f64, 0.0);
        planets[idx].update_position();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...