2016-11-29 2 views
7

struct에 다른 유형에 대한 참조 인 멤버 변수를 제공하는 데 문제가 있습니다. 플레이어는 그들이에있는 현재 Cell에 대한 참조가벡터의 요소에 대한 참조

struct Player<'a> { 
    current_cell: &'a Cell, 
} 

impl<'a> Player<'a> { 
    pub fn new(starting_cell: &'a Cell) -> Player<'a> { 
     Player { current_cell: starting_cell } 
    } 
} 

여기 내 Game 구조체 및 그 구현 : :. 여기 내 구조체 및 구현은

struct Game { 
    is_running: bool, 
    cells: Vec<Cell>, 
} 

impl Game { 
    pub fn new() -> Game { 
     let cells = construct_cells(); 
     let player = Player::new(cells[0]); 

     Game { 
      is_running: false, 
      cells: cells, 
     } 
    } 
} 

cellsCell의 벡터이다 에스. 게임을 만들 때 construct_cells()에 셀 벡터를 만든 다음 첫 번째 셀에서 플레이어를 시작합니다. 나는 점점 오전 오류는 다음과 같습니다

expected &Cell, found struct `Cell` 

나는 내가 Player를 만들 때 내가 참조를 전달 아니에요 것을 볼 수 있습니다,하지만 난 &cells[0]에 매개 변수를 변경하면 다음 전체 벡터를 빌리는 나를 으악 및 그런 다음 Game 구조체를 만들 때 다시 사용하려고합니다. 무슨 일 이니? 플레이어에게 Cell에 대한 참조를 제공하려면 어떻게해야합니까?

+0

어떤 참조 (또는 포인터)가 있는지, 특히 매달려있는 참조 * (또는 포인터)가 무엇인지 잘 알고 있습니까? 친구에게 주소 (123 Main St.)가 적힌 종이를 준 다음 ** 이사 ** 한 경우 어떻게됩니까?당신의 친구가 방금 나타나서 당신이 살았던 집에있는 사람들과 당신과 이야기를 나누기 시작했다면 어떻게 그 집의 새 주인이 느끼겠습니까? – Shepmaster

+0

@Shepmaster 나는 매달린 포인터가 무엇인지 압니다. 나는이 솔루션이 하나를 허용 할 수 있다는 것을 몰랐다. 그렇다면 어떻게 동일한 결과를 얻을 수 있습니까? 내가 할 수있는 일이 가능합니까? – Dooskington

+1

* 나는이 솔루션이 하나의 *를 허용 할 수 있음을 깨닫지 못했습니다. 그래서 녹이 멋진 언어 인 IMO입니다. 지역 변수에서'cell'을'Game' 구조체로 옮기면,'player'에 부여한 것과 같은 벡터에 대한 참조가 무효화됩니다. C 또는 C++과 같은 언어를 사용하면 AFAIK을 수행 할 수 있으며 런타임에 코드를 충돌시킬 수 있습니다. 'player'는 결코 사용되지 않기 때문에 당신이 정말로하고 싶은 것을 말하기는 어렵습니다. – Shepmaster

답변

10

외형에도 불구하고 변경 가능한 벡터에 저장된 객체에 대한 참조를 저장하는 것은 이 아니며이 아닙니다. 벡터는 자랄 수 있음을 기억하십시오. 벡터가 용량을 초과하면 더 큰 배열을 할당하고 모든 객체를 새 위치로 이동하여이 벡터를 확장합니다. 벡터에있는 객체에 대한 참조는 매달려 있어야하며 Rust는이를 허용하지 않습니다. (또한 벡터를 축소하거나 지울 수 있습니다.이 경우 해당 요소에 대한 참조는 분명히 할당 취소 된 메모리를 가리 킵니다.) C++ std::vector에도 같은 문제가 있습니다.

주위에는 여러 가지 방법이 있습니다. 하나는 Game에 백 포인터와 벡터 요소에 대한 인덱스 구성 안전한 백 레퍼런스 Cell에 직접 참조로 전환하는 것이다

struct Player<'a> { 
    game: &'a Game, 
    cell_idx: usize, 
} 

impl<'a> Player<'a> { 
    pub fn new(game: &'a Game, cell_idx: usize) -> Player<'a> { 
     Player { 
      game: game, 
      cell_idx: cell_idx, 
     } 
    } 
    pub fn current_cell_name(&self) -> &str { 
     &self.game.cells[self.cell_idx].name 
    } 
} 

전체 컴파일 가능한 예 at the playground이다.

위의 내용은 부정 행위처럼 보일 수 있습니다. 결국 Rust는 참조가있는 시스템 언어이고 인덱스를 사용하는 것은 다소 복잡합니다. 더 잘할 수 있을까요?

또 다른 옵션은 Cell 개체가 벡터 재 할당의 영향을받지 않도록하기위한 추가 노력을 투자하는 것입니다. C++에서 하나의 포인터 - 투 - 세포 대신 세포의 벡터의 벡터를 사용하여 해당를 달성 할 것이며, 녹에 우리는 상자 사용하여 동일한 작업을 수행 할 수 있습니다의 비용으로

struct Game { 
    is_running: bool, 
    cells: Vec<Box<Cell>>, 
} 

impl Game { 
    fn construct_cells() -> Vec<Box<Cell>> { 
     ["a", "b", "c"].iter() 
      .map(|n| Box::new(Cell { name: n.to_string() })) 
      .collect() 
    } 

    pub fn new() -> Game { 
     let cells = Game::construct_cells(); 

     Game { 
      is_running: false, 
      cells: cells, 
     } 
    } 
} 

을 다시

struct Player<'a> { 
    cell: &'a Cell, 
} 

impl<'a> Player<'a> { 
    pub fn new(cell: &'a Cell) -> Player<'a> { 
     Player { 
      cell: cell, 
     } 
    } 
    pub fn current_cell_name(&self) -> &str { 
     &self.cell.name 
    } 
} 

전체 컴파일 가능한 예 at the playgroundCell 추가 할당 (각 셀에서 Game 추가적인 포인터 역 참조),이 Player 최대한의 효과적인 구현을 허용한다.

관련 문제