我正在重写Rust 1.6中的现有代码,并且我发现在源语言中通过typedef标记类型非常方便。举例来说,在我的纸牌游戏,我已经定义了F#中排名值:Rust是否具有与F#typedefs相同的习惯用法?
type Rank = uint8
我正在重写Rust 1.6中的现有代码,并且我发现在源语言中通过typedef标记类型非常方便。举例来说,在我的纸牌游戏,我已经定义了F#中排名值:Rust是否具有与F#typedefs相同的习惯用法?
type Rank = uint8
从The Rust Programming Language标题为`type` Aliases:
的
type
关键字可以声明另一个类型的别名:type Name = String;
,就好像它是一个真正的类型,你可以使用这个类型:
type Name = String; let x: Name = "Hello".to_string();
还有更多的你应该阅读,但这回答了这个问题。
作为一种编辑方式,我不认为类型别名很适合人们使用它们的很多地方。假设你的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,()> {
let r = match v {
1 => One,
2 => Two,
// ...
_ => return Err(()),
};
Ok(r)
}
fn value(&self) -> u8 {
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> {
// ..
}
感谢您的快速和详细的回复!通常我非常同意你使用枚举将我的值限制为标准套牌值。不过,就我而言,我一般使用“卡”一词,而不是纸牌,所以我需要一个未指定值的等级。 我是否正确理解我应该使用类型别名,如果我想要简单替换,以及如果我想要施加其他限制/逻辑,则使用新类型? –
@ErikUggeldahl是的,这听起来正确。新类型允许额外的限制或逻辑,而别名就是这样,另一个名字就是同一个名字。 – Shepmaster
@ErikUggeldahl它不仅限制了值。别名不提供额外的类型安全性,因为它不是...新类型,但同一类型的另一个名称。你能够计算一个'Rank/5'或将一个'Rank'传递给一个需要'u8'的函数吗?因为类型别名允许你这样做(因为'Rank' *是* u8')。你通常在Rust中使用类型别名是为了方便,当你有一个非常长和复杂的类型并且想要更简洁地引用它时(但别名*是*类型并且应该用来代替它到处) –