Rust: присвойте Enum самому себе со специализацией Generics

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

pub trait MyEnumState{}

// All state are Zero Sized Type
pub struct State1; impl MyEnumState for State1{};
pub struct State2; impl MyEnumState for State2{};

// Note : I don't know is there is a PhantomData<S> for an enum
pub enum MyEnum<S: MyEnumState> {
    A,
    B,
    C(i32), // Can also have some data
    // ... long enum
}

Теперь я хотел бы иметь возможность их разыгрывать: одно и то же значение, другой тип.

// How to avoid this mess ???
impl MyEnum<State1> {
    pub fn to_state2(self) -> MyEnum<State2> {
        match self {
            MyEnum::A => MyEnum::A,
            MyEnum::B => MyEnum::B,
            MyEnum::C(v) => MyEnum::C(v),
        }
    }
}

// I can proably make a generic function
// ```
// fn cast
//     <StateBegin : MyEnumState, StateEnd : MyEnumState>
// (val MyEnum<StateBegin>) -> MyEnum<StateEnd> { ... }
// ```
// to avoid repetition but I still have at least 1 giant match to implement
impl MyEnum<State2> { ... }



impl<S : MyEnumState> MyEnum<S> 
{
   pub fn to_state<NewState : MyEnumState>(self) ->  MyEnum<NewState> 
   {
      // how ?!
   }
}

Это всего лишь простой пример. Цель состоит в том, чтобы иметь 0 операторов сопоставления, чтобы избежать совпадений для всех существующих вариантов перечисления.

Как например State1 состояние, когда оно ничего не содержит?

true equals false 16.04.2024 16:55

Потому что вы можете реализовать другую функцию, если у вас есть MyEnum<State1> или MyEnum<State2>. impl MyEnum<State1>{ fn foo(&self) {} }impl MyEnum<State2>{ fn bar(&self) {} } Вы можете поискать в Интернете по запросу «машина состояния ржавчины», чтобы увидеть потрясающее использование нулевого типа :)

Thomas 16.04.2024 17:46

@trueequalsfalse это называется шаблоном состояния типа, и State1, поскольку он другого типа, чем State2, может включать другую обработку MyEnum<State1> и MyEnum<State2>, очевидно, его можно использовать только во время компиляции, поскольку после этого информация о типе больше не доступна.

cafce25 16.04.2024 17:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Один из способов — поместить поле PhantomData за пределы перечисления в структуру-оболочку:

use core::marker::PhantomData;

pub enum MyEnum {
    A,
    B,
    C(i32),
}

pub struct EnumWithState<S: MyEnumState> {
    data: MyEnum,
    _state: PhantomData<S>,
}

Затем вы можете реализовать функцию приведения типов на EnumWithState:

impl<S: MyEnumState> EnumWithState<S> {
    fn to_state<S2: MyEnumState>(self) -> EnumWithState<S2> {
        EnumWithState {
            data: self.data,
            _state: PhantomData,
        }
    }
}

Другие вопросы по теме