2015-06-06 8 views
7

Aşağıdaki, etrafında dönen iki topun bulunduğu dikdörtgen alanlı bir alanla basit bir simülasyondur. Field yapısının, her bir topuna update adını veren bir update yöntemine sahiptir. Toplar, update yönteminde, hızlarına göre hareket etmelidir. Ama aynı zamanda ben Ball yapı güncelleme işlevine sınırları ve diğer topun hakkında bilgi almak nasıl alanda .:Değiştirilebilir öz referansı sahip olunan nesnenin yöntemine geçirme

fn main() { 
    let mut field = Field::new(Vector2d { x: 100, y: 100 }); 
    field.update(); 
} 

#[derive(Copy, Clone)] 
struct Vector2d { 
    x: i32, 
    y: i32, 
} 

struct Ball { 
    radius: i32, 
    position: Vector2d, 
    velocity: Vector2d, 
} 

impl Ball { 
    fn new(radius: i32, position: Vector2d, velocity: Vector2d) -> Ball { 
     Ball { 
      radius: radius, 
      position: position, 
      velocity: velocity, 
     } 
    } 

    fn update(&mut self, field: &Field) { 
     // check collisions with walls 
     // and other objects 
    } 
} 

struct Field { 
    size: Vector2d, 
    balls: [Ball; 2], 
} 

impl Field { 
    fn new(size: Vector2d) -> Field { 
     let position_1 = Vector2d { 
      x: size.x/3, 
      y: size.y/3, 
     }; 
     let velocity_1 = Vector2d { x: 1, y: 1 }; 
     let position_2 = Vector2d { 
      x: size.x * 2/3, 
      y: size.y * 2/3, 
     }; 
     let velocity_2 = Vector2d { x: -1, y: -1 }; 

     let ball_1 = Ball::new(1, position_1, velocity_1); 
     let ball_2 = Ball::new(1, position_2, velocity_2); 

     Field { 
      size: size, 
      balls: [ball_1, ball_2], 
     } 
    } 

    fn update(&mut self) { 
     // this does not compile 
     self.balls[0].update(self); 
     self.balls[1].update(self); 
    } 
} 

yanı sıra sınırları birbirine tepki gerekir?

error[E0502]: cannot borrow `*self` as immutable because `self.balls[..]` is also borrowed as mutable 
    --> src/main.rs:62:30 
    | 
62 |   self.balls[0].update(self); 
    |   -------------  ^^^^- mutable borrow ends here 
    |   |     | 
    |   |     immutable borrow occurs here 
    |   mutable borrow occurs here 

Bunu anlayışla karşılıyorum, ama bunun üstesinden nasıl bilmiyorum:

self.balls[0].update(self); 
self.balls[1].update(self); 

aşağıdaki hatayı verilmesi: Field::update bu satırlar, derlemek yoktur.

cevap

6

Sizin Ball yapınız, Field ürününü bilmenizle birlikte güncellenmesi gerekmektedir. Bu, derleme yapmaz çünkü sonuç mutasyonla birleştirilmiş döngüsel referanslar olacaktır. Bu işi Cell veya RefCell (ikincisi bir performans maliyetine sahip) kullanarak yapabilirsiniz, ancak kodu daha farklı bir şekilde yapılandırmak daha da iyi olacaktır.yapısını denetleyin ve Ball - Ball ve Ball - Wall çarpışmalarını kontrol edin. Ball yapısının update işlevi, Ball'un konumunu güncelleştirmeyi işleyebilir.

// Ball's update function 
fn update(&mut self) { 
    // update position 
} 

// Field's update function 
fn update(&mut self) { 
    for ball in self.balls.iter_mut() { 
     ball.update(); 
    } 

    // check for collisions 

    // resolve any collisions 
} 
+1

Evet, çalışacaktır . Dostum, Rust gerçekten programlamam konusunda farklı düşünmemi sağlıyor. –

1

İşte küçük bir örnek:

struct Ball { 
    size: u8, 
} 

impl Ball { 
    fn update(&mut self, field: &Field) {} 
} 

struct Field { 
    ball: Ball, 
} 

impl Field { 
    fn update(&mut self) { 
     self.ball.update(self) 
    } 
} 

kök sorun Field kitabına atıfta bulunarak geçtiğinde, sen Field (içinde değişmez kısmını değiştirmek olamayacağını garanti hale getirmesidir "değişmez referans"). Bununla birlikte, bunun bir parçasını mutasyona uğratmaya da çalışıyorsunuz: top! Ball::update'un uygulanmasında hangi referans yetkili, self veya field olmalıdır?

bir çözüm update için gerekli yapının ayrı parçalar olduğu ve bu değil ve update fonksiyonunu çağırarak önce onları kullanın:

struct Ball { 
    size: u8, 
} 

impl Ball { 
    fn update(&mut self, field: &u8) {} 
} 

struct Field { 
    players: u8, 
    ball: Ball, 
} 

impl Field { 
    fn update(&mut self) { 
     self.ball.update(&self.players) 
    } 
} 

Hatta düzenli pakete bu parça parça başvuruları paketlemek edebilirsiniz :

struct Ball { 
    size: u8, 
} 

impl Ball { 
    fn update(&mut self, field: BallUpdateInfo) {} 
} 

struct BallUpdateInfo<'a> { 
    players: &'a u8, 
} 

struct Field { 
    players: u8, 
    ball: Ball, 
} 

impl Field { 
    fn update(&mut self) { 
     let info = BallUpdateInfo { players: &self.players }; 
     self.ball.update(info) 
    } 
} 

Ya baştan bilgilerini ayırmak için içeren yapı yeniden:

struct Ball { 
    size: u8, 
} 

impl Ball { 
    fn update(&mut self, field: &UpdateInfo) {} 
} 

struct UpdateInfo { 
    players: u8, 
} 

struct Field { 
    update_info: UpdateInfo, 
    ball: Ball, 
} 

impl Field { 
    fn update(&mut self) { 
     self.ball.update(&self.update_info) 
    } 
} 

Ayrıca diğer yol ve ona herhangi bir değişiklik yapmadan önce Field den Ball kaldırabilir.Kolayca/ucuza bir Ball yapabiliyorsanız, bunu değiştirmeyi deneyin: kolayca birini yapamıyorsanız

use std::mem; 

struct Ball { 
    size: u8, 
} 

impl Ball { 
    fn update(&mut self, field: &Field) {} 
} 

impl Default for Ball { 
    fn default() -> Ball { 
     Ball { size: 0 } 
    } 
} 

struct Field { 
    ball: Ball, 
} 

impl Field { 
    fn update(&mut self) { 
     let mut ball = mem::replace(&mut self.ball, Ball::default()); 
     ball.update(self); 
     self.ball = ball; 
    } 
} 

, bir Option ve take, kullanabileceği:

struct Ball { 
    size: u8, 
} 

impl Ball { 
    fn update(&mut self, field: &Field) {} 
} 

struct Field { 
    ball: Option<Ball>, 
} 

impl Field { 
    fn update(&mut self) { 
     if let Some(mut ball) = self.ball.take() { 
      ball.update(self); 
      self.ball = Some(ball); 
     } 
    } 
}