Как мне вернуть массив объектов с помощью `impl Trait` из функции без бокса? - PullRequest
0 голосов
/ 26 мая 2018

Я внедряю ящик для судоку, и я хотел бы допустить возможность судоку более высокого измерения.В 2-х измерениях есть 3 группы, которые необходимо проверить на корректность (простое правило содержит только 3 подправила), а для положения (по определению) требуются только 2 координаты, но в более высоких измерениях это очевидно увеличивается.

Я написал следующую сигнатуру метода, но она не работает, и я хотел бы избежать упаковки любой ценой из-за сред, для которых я разрабатываю.

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

Фактический типкаждой группы будет известно во время компиляции (фактический тип будет выглядеть примерно так: [Box, Stack, Band]), но, похоже, компилятору это не понравится, даже если он будет знать размер каждого элемента.

Мне бы очень хотелось иметь возможность использовать кортеж с размером, определенным во время компиляции, но это, кажется, не так легко поддерживать, если я что-то упустил.


Идея состоит в том, чтоЕсть три типа Group: Stack (столбец), Band (строка) и Box.Определение для Group дано ниже.

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>>;
}

Начнем с двумерного случая.Для данного элемента мы можем записать индекс элемента в виде двойного (т. Е. 2-кортежа) (x, y).Группы, ассоциированные с этим элементом, представляют собой одну Box (как всегда; отсюда DIMENSION + 1), одну Stack и одну Band.

В трех измерениях данный элементиндексируется (по определению) тройкой (т. е. 3-кортеж) (x, y, z).В этом случае группы, связанные с этим элементом: одна Box, одна Stack и две Band с.

Эта тенденция продолжается в более высоких измерениях, и я хочу включитьпользователь может использовать другую размерность - таким образом, определение размеров во время компиляции.

Чтобы проверить правильность головоломки, вызывающий просто вызывает Group::is_valid() для каждого из puzzle.groups();они также могут перебирать каждый из них, чтобы отобразить загадку соответствующим образом.

1 Ответ

0 голосов
/ 26 мая 2018

Вы не можете, потому что все 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, вероятно, не может быть выведен, если он не может быть выведен из call-сайта (например, let x: [SomeGroup; 3] = groups([...])), поэтому вам необходимо явно указать типс groups::<SomeGroup>([...]).

Я не знаю, является ли это именно тем, что вы хотите, но это отражает общую идею, что вам нужно установить массив некоторого фиксированного типа.То есть [T; N] фиксируется на T, тогда как [impl Trait; N] будет означать, что каждый элемент может быть любого типа, который реализует Trait, что само по себе подразумевает, что это гетерогенный массив, но массивы вРжавчина однородна.

Я не могу сказать, хотите ли вы также параметризовать константу DIMENSIONS, для чего требуется RFC 2000: общие константы , которые AFAIK еще не реализованы, дажев ночной.Вам, вероятно, это не нужно, если вы можете вывести его из параметра, как вы, похоже, делаете.

pub fn groups<T: Group, const DIMENSIONS: usize>(position: [u8; DIMENSIONS])
  -> [T; DIMENSIONS + 1]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...