2017-01-22 12 views
2

Есть ли способ сделать что-то подобное?Есть ли способ создать псевдоним значения перечисления?

enum MyType { 
    Left, 
    Right, 

    #[cfg(universe = "normal")] 
    Port = Left, 
    #[cfg(universe = "normal")] 
    Starboard = Right, 

    #[cfg(universe = "mirror")] 
    Port = Right, 
    #[cfg(universe = "mirror")] 
    Starboard = Left, 

} 

Если вы на самом деле попробовать, вы получите эту ошибку (я должен был добавить MyType::):

error[E0080]: constant evaluation error 
--> <anon>:9:12 
    | 
9 |  Port = MyType::Left, 
    |   ^^^^^^^^^^^^ unimplemented constant expression: enum variants 

Here где запускается эта ошибка.

ответ

1

Ваша реализация не имеет никакого смысла. Посмотрите на более простой версии:

enum MyType { 
    One, 
    Two = One, 
} 

Или сказал другому:

enum MyType { 
    One = 1, 
    Two = 1, 
} 

Вы просите компилятор создать два варианта перечисления, которые являются одинаковыми. Но весь смысл перечислений состоит в том, что они являются эксклюзивными друг друга.

Вместо этого, просто создать константу:

enum MyType { 
    One, 
} 

const TWO: MyType = MyType::One; 
+0

Да, я пытаюсь создать псевдонимы. У Rust уже есть псевдонимы типов без проблем. Можете ли вы привести пример того, как поддержка псевдонимов вариантов перечисления может сломать что-то, потому что я не вижу ничего. – Timmmm

+0

@Timmmm: Проблема заключается в сопоставлении с образцом. Какой рычаг берется в случае, если у вас есть совпадение x {One => {}, Two => {}} '? –

+0

Это не проблема. Он будет вести себя точно так, как если бы вы написали «match x {One => {}, One => {}}', т. Е. Распечатали ошибку. (Ошибка, которую он на самом деле печатает, это 'Это недостижимый шаблон'.) – Timmmm

2

Нет, насколько я знаю.

Перечисления в ржавчине - это не «пучок постоянных значений», как в C. Существует поддержка связывания числовых значений с константами, но это все. Конечно, вы могли бы создавать константы любого имени, но они не позволяли бы шаблону сопоставлять значение перечисления.

В известном смысле псевдоним в варианте перечисления немного напоминает псевдоним в поле типа. Я никогда не видел появления одного поля, идентифицированного двумя именами; Интересно, есть ли какой-нибудь язык, который его поддерживает.


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

use std::convert::From; 

enum Side { 
    Left, 
    Right, 
} 

enum PortSide { 
    Port, 
    Starboard, 
} 

#[cfg(not(universe = "mirror"))] 
impl From<Side> for PortSide { 
    fn from(s: Side) -> PortSide { 
     match s { 
      Side::Left => PortSide::Port, 
      Side::Right => PortSide::Starboard, 
     } 
    } 
} 

#[cfg(universe = "mirror")] 
impl From<Side> for PortSide { 
    fn from(s: Side) -> PortSide { 
     match s { 
      Side::Left => PortSide::Starboard, 
      Side::Right => PortSide::Port, 
     } 
    } 
} 

Кроме того, я бы посоветовал вам не требуется возможность быть определены , но вместо этого разрешить поведение по умолчанию при отсутствии этой функции. В вашем случае «нормальный» кажется, что это должно быть поведение по умолчанию.

+0

Я думал о рекомендации вторичного перечисления. Кажется, что бывают случаи, когда вам нужно одно представление или другое, но не одновременно. – Shepmaster

+0

C "поддерживает" псевдонимы и псевдонимы полей структуры, используя препроцессор. Я просто полушум здесь - классические реализации Unix, например. 'struct stat' использует эту функцию * много *, и это часть причины, по которой строковые и объединенные поля префиксны (другая часть состоит в том, что она защищает стандартную библиотеку от * приложения * #defining что-то, что происходит с конструкцией поле). – user4815162342