Vector 实现二维向量语法以访问一维向量?
我正在制作一个类似roguelike的玩具,并且有一个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向量 为了做到这一点,我需要为我的类实现索引特性,但我不确定如何获得我想要的结果。可能通过
级别
结构来存储游戏地图,最简单的实现是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 }
}