我正在重写Rust 1.6中的现有代码,我发现在源语言中使用typedef标记类型非常方便。例如,在我的纸牌游戏中,我将F#中的等级值定义为:
type Rank = uint8
答案 0 :(得分:21)
标题为The Rust Programming Language的Creating Type Synonyms with Type Aliases部分:
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
或newtype。原因是使用类型别名可以执行以下操作:
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,
// ...
}
}
}
newtype 只是一个包装类型。与包装类型相比,它不会消耗额外的空间,它只提供一个实际的新类型,允许您实现可以限制为有效值的方法。可以创建无效值,但仅限于您自己的代码,而不是所有客户端代码:
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
等类型,您可以see in the standard library进行此操作。类似的东西:
type CardResult<T> = Result<T, Error>;
fn foo() -> CardResult<String> {
// ..
}