Я переписываю существующий код моего в Rust 1.6, и я нашел очень удобным в исходном языке ярлык типа typedef. Например, в моей карточной игре у меня есть значение ранга в F #, определяемое как:
type Rank = uint8
Я переписываю существующий код моего в Rust 1.6, и я нашел очень удобным в исходном языке ярлык типа typedef. Например, в моей карточной игре у меня есть значение ранга в F #, определяемое как:
type Rank = uint8
Из раздела " Язык программирования Rust " под названием " Создание синонимов типов с псевдонимами типов":
Rust предоставляет возможность объявить псевдоним типа, чтобы присвоить существующему типу другое имя. Для этого мы используем ключевое слово type
. Например, мы можем создать псевдоним Kilometers
для i32
следующим образом:
type Kilometers = i32;
Теперь псевдоним Kilometers
является синонимом i32
; [...], Kilometers
не отдельный, новый тип. Значения с типом Kilometers
будут обрабатываться так же, как значения типа i32
:
type Kilometers = i32;
let x: i32 = 5;
let y: Kilometers = 5;
println!("x + y = {}", x + y);
Там больше, что вы должны прочитать, но это отвечает на вопрос.
Как часть редакционной статьи, я не думаю, что псевдоним типа отлично подходит во многих местах, где люди его используют. Предполагая, что ваш тип Rank
представляет собой что-то общее с колодой карт, я бы предложил либо enum
либо новый тип. Причина в том, что с псевдонимом типа вы можете сделать что-то вроде этого:
let rank: Rank = 100;
Что бессмысленно для типичной колоды карт. Перечисление является ограниченным набором. Это означает, что вы никогда не сможете создать недействительный Rank
:
enum Rank {
One, Two, Three, Four, Five,
Six, Seven, Eight, Nine, Ten,
Jack, Queen, King, Ace,
}
impl Rank {
fn from_value(v: u8) -> Result<Rank, ()> {
use Rank::*;
let r = match v {
1 => One,
2 => Two,
// ...
_ => return Err(()),
};
Ok(r)
}
fn value(&self) -> u8 {
use Rank::*;
match *self {
One => 1,
Two => 2,
// ...
}
}
}
Новый тип - это просто тип оболочки. Он не потребляет дополнительного пространства по сравнению с переносимым типом, он просто предоставляет фактический новый тип, который позволяет реализовывать методы, которые могут ограничиваться допустимыми значениями. Возможно создать недопустимые значения, но только в пределах вашего собственного кода, а не всего клиентского кода:
struct Rank(u8);
impl Rank {
fn from_value(v: u8) -> Result<Rank, ()> {
if v >= 1 && v <= 14 {
Ok(Rank(v))
} else {
Err(())
}
}
fn value(&self) -> u8 {
self.0
}
}
Я склонен использовать псевдонимы типов как быстрые заполнители типов. При написании приведенных выше примеров, я на самом деле написал:
type Error = ();
И вернул Result<Rank, Error>
, но потом подумал, что это сбивает с толку. :-)
Другой случай, который я использую, - это укоротить шрифт большего размера, который я не хочу скрывать. Это происходит с такими типами, как итераторы или Result
, которые вы можете увидеть в стандартной библиотеке. Что-то вроде:
type CardResult<T> = Result<T, Error>;
fn foo() -> CardResult<String> {
// ..
}