如何在没有装箱的情况下使用`impl Trait`返回一个对象数组?

时间:2018-05-26 01:45:59

标签: rust

我正在实施一个Sudoku箱子,我想允许更高维度的Sudokus。在2维中,有3组需要检查正确性(主要规则只包含3个子规则)和位置(按定义)只需要2个坐标来完全指定,但在更高的维度,这显然会增加。

我写了下面的方法签名,但它不起作用,我想不惜一切代价避免拳击,因为我正在开发的环境。

pub fn groups(position: [u8; DIMENSIONS]) -> [impl Group; DIMENSIONS + 1]

每个组的实际类型在编译时都是已知的(实际类型将类似于[Box, Stack, Band]),但看起来编译器不喜欢这个,即使它知道它的大小每个元素。

我希望能够使用在编译时确定大小的元组,但这似乎并不容易支持,除非我遗漏了一些东西。

我们的想法是three types of GroupStack(列),Band(行)和BoxGroup的定义如下。

pub trait Group {
    /// A group is considered valid if it has contains only unique elements.
    fn is_valid(&self) -> bool { /* Default implementation elided. */ }
    /// Returns an owned copy of the group's constituent elements.
    fn elements(&self) -> Vec<Option<Element>>;
}

让我们从二维案例开始。对于给定元素,我们可以将元素的索引写为double(即2元组)(x, y)。与此元素相关联的组是一个Box(一如既往;这是DIMENSION + 1来自的地方),一个Stack和一个Band

在三维中,给定元素(按照定义)被三元组(即3元组)(x, y, z)索引。与此元素相关联的组是一个Box,一个Stack两个 Band

这种趋势持续到更高的维度,我想让用户使用不同的维度 - 从而确定大小的编译时间。

要检查拼图是否正确,来电者只需在Group::is_valid()的每一个上调用puzzle.groups();他们也可以迭代每个以适当地渲染拼图。

1 个答案:

答案 0 :(得分:3)

你不能因为所有impl Trait保证是它实现Trait的某种类型。 Rust中的数组是同构的,每个元素必须是相同的类型,但[impl Group; DIMENSIONS + 1]之类的意思是每个元素可以是任何类型,只要它实现Group

没有更多代码很难说,但这可以通过参数化Group的类型来实现:

pub fn groups<T: Group>(position: [u8; DIMENSIONS]) -> [T; DIMENSIONS + 1]

现在,groups()函数的一个实例会针对调用T的每种Group进行单态化。这导致返回的数组仅固定为该类型,允许它是同类的。由于该函数没有T类型的参数,因此除非可以从调用站点推断出(T),否则可能无法推断let x: [SomeGroup; 3] = groups([...])的类型,因此您需要使用groups::<SomeGroup>([...])明确指定类型。

我不知道这是否正是您想要的,但它传达了您需要将数组设置为某种固定类型的一般想法。也就是说,[T; N]固定为T,而[impl Trait; N]意味着每个元素都可以是实现Trait的任何类型,这本身就意味着它是一个异构数组,但Rust中的数组是同类的。

我无法判断您是否还想要对常量DIMENSIONS进行参数化,这需要RFC 2000: const generics即使在夜间也未实现AFAIK。如果您能够从参数中推断出来,那么您可能并不需要这样做。正如您似乎正在做的那样。

pub fn groups<T: Group, const DIMENSIONS: usize>(position: [u8; DIMENSIONS])
  -> [T; DIMENSIONS + 1]