Vector 实现二维向量语法以访问一维向量?

Vector 实现二维向量语法以访问一维向量?,vector,syntax,rust,operator-overloading,Vector,Syntax,Rust,Operator Overloading,我正在制作一个类似roguelike的玩具,并且有一个级别结构来存储游戏地图,最简单的实现是2D向量 下面我将使用一个矢量矢量,但声明为了提高性能,也可以使用一个大小为MAP\u HEIGHT*MAP\u WIDTH的矢量,并访问(x,y)的平铺,只需访问MAP[y*MAP\u WIDTH+x] 我试图实现这个更快的方法,但是使用getter和setter很麻烦,公共字段也不是很好。我更喜欢它感觉像一个2D向量 为了做到这一点,我需要为我的类实现索引特性,但我不确定如何获得我想要的结果。可能通过

我正在制作一个类似roguelike的玩具,并且有一个
级别
结构来存储游戏地图,最简单的实现是2D向量

下面我将使用一个
矢量
矢量
,但声明为了提高性能,也可以使用一个大小为
MAP\u HEIGHT*MAP\u WIDTH
矢量
,并访问
(x,y)
的平铺,只需访问
MAP[y*MAP\u WIDTH+x]

我试图实现这个更快的方法,但是使用getter和setter很麻烦,公共字段也不是很好。我更喜欢它感觉像一个2D向量

为了做到这一点,我需要为我的类实现
索引
特性,但我不确定如何获得我想要的结果。可能通过嵌套
impl
s?我真的不知道

下面是我的代码,它试图为我的结构实现
索引
,但这显然不符合我的目的,因为它是一维的:

const MAP_WIDTH: i32 = 80;
const MAP_HEIGHT: i32 = 45;

pub struct Level {
    map: Vec<Tile>,
}

impl Level {
    pub fn new() -> Self {
        Level { map: vec![Tile::empty(); (MAP_HEIGHT * MAP_WIDTH) as usize] }
    }
}

impl std::ops::Index<i32> for Level {
    type Output = Tile;
    fn index(&self, x: i32) -> &Self::Output {
        self[MAP_WIDTH + x]; // We have x and y values; how do we make this work?
    }
}
const MAP\u WIDTH:i32=80;
常量地图高度:i32=45;
发布结构级别{
地图:Vec,,
}
impl级别{
pub fn new()->Self{
级别{map:vec![Tile::empty();(映射高度*映射宽度)as usize]}
}
}
impl std::ops::级别索引{
类型输出=瓷砖;
fn索引(&self,x:i32)->&self::输出{
self[MAP_WIDTH+x];//我们有x和y值;我们如何使其工作?
}
}

使结构在
(i32,i32)
类型的对象上不灵活


由于您使用的是
i32
,因此需要确保值在范围内,并且可以强制使用
usize
,这就是
Vec
的索引。也许您应该从一开始就坚持使用
u32
usize
值。否则,您需要跟踪最小的
x
y
值,然后减去它们,以保持位置在范围内。处理正坐标并假设地图的一角是
(0,0)

如果不公开实现的内部细节,就无法做到这一点<代码>索引
定义为:

pub trait Index<Idx> 
where
    Idx: ?Sized, 
{
    type Output: ?Sized;
    fn index(&self, index: Idx) -> &Self::Output;
}
这可以用作
级别[(43,12)]



如果您这样做,您应该意识到您永远都在要求内部数据结构是基于切片的。例如,不能使用类似于
HashMap
的“稀疏”结构,因为它不能返回
&[Tile]
。返回
&[Tile]
的功能现在是结构的公共API的一部分。当然,表示形式可能会改变,特别是因为它已经改变过一次。

这是可能的,但并不明显

首先,我建议在
usize
中使用
MAP\u WIDTH
MAP\u HEIGHT
,因为它们是正整数:

const MAP_WIDTH: usize = 80;
const MAP_HEIGHT: usize = 45;
然后需要实现
索引
(可能还有
IndexMut
)来返回一个切片;在本例中,我假设您希望第一个坐标为行:

impl std::ops::Index<usize> for Level {
    type Output = [Tile];

    fn index(&self, row: usize) -> &[Tile] {
        let start = MAP_WIDTH * row;
        &self.map[start .. start + MAP_WIDTH]
    }
}

impl std::ops::IndexMut<usize> for Level {
    fn index_mut(&mut self, row: usize) -> &mut [Tile] {
        let start = MAP_WIDTH * row;
        &mut self.map[start .. start + MAP_WIDTH]
    }
}

谢谢!你是对的,因为
libtcod
0,0
映射到屏幕的左上角(这意味着你不能,或者更确切地说,你不想进入
0,0
)如果
i32
,我应该使用
u32
。在我的游戏
平铺
s中存储两个
bool
s、
blocked
block\u>。有关其位置的信息位于向量中。但是谢谢你的帮助。我想我现在只使用一个元组,因为它更容易理解,但我肯定会保存这个片段供以后使用。@Boiethios你是对的,这实际上解决了我所问的问题,所以即使我使用元组,我也会接受这个答案。你应该知道,通过这样做,您总是要求您的内部数据结构是基于切片的。例如,不能使用类似于
HashMap
的“稀疏”结构,因为它不能返回
&[Tile]
。返回
&[Tile]
的功能现在是结构的公共API的一部分。表示肯定会改变,特别是因为OP已经改变了一次表示。@Shepmaster如果这是一个问题,OP只需要创建自己的结构
,实现
索引
级别
--Index-->
--Index-->
平铺
impl std::ops::Index<(usize, usize)> for Level {
    type Output = Tile;
    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
        &self.map[MAP_WIDTH as usize * y + x]
    }
} 
const MAP_WIDTH: usize = 80;
const MAP_HEIGHT: usize = 45;
impl std::ops::Index<usize> for Level {
    type Output = [Tile];

    fn index(&self, row: usize) -> &[Tile] {
        let start = MAP_WIDTH * row;
        &self.map[start .. start + MAP_WIDTH]
    }
}

impl std::ops::IndexMut<usize> for Level {
    fn index_mut(&mut self, row: usize) -> &mut [Tile] {
        let start = MAP_WIDTH * row;
        &mut self.map[start .. start + MAP_WIDTH]
    }
}
const MAP_WIDTH: usize = 80;
const MAP_HEIGHT: usize = 45;

#[derive(Clone, Debug)]
pub struct Tile {
    x: u32,
    y: u32
}

pub struct Level {
    map: Vec<Tile>,
}

impl Level {
    pub fn new() -> Self {
        Level { map: vec![Tile { x: 0, y: 0 }; (MAP_HEIGHT * MAP_WIDTH) as usize] }
    }
}

impl std::ops::Index<usize> for Level {
    type Output = [Tile];

    fn index(&self, row: usize) -> &[Tile] {
        let start = MAP_WIDTH * row;
        &self.map[start .. start + MAP_WIDTH]
    }
}

impl std::ops::IndexMut<usize> for Level {
    fn index_mut(&mut self, row: usize) -> &mut [Tile] {
        let start = MAP_WIDTH * row;
        &mut self.map[start .. start + MAP_WIDTH]
    }
}

fn main() {
    let mut lvl = Level::new(); 

    lvl[5][2] = Tile { x: 5, y: 2 };

    println!("{:?}", lvl[5][2]); // Tile { x: 5, y: 2 }
}