Rust是否具有与F#typedef等效的惯用语?

时间:2016-01-22 03:19:33

标签: types rust type-alias

我正在重写Rust 1.6中的现有代码,我发现在源语言中使用typedef标记类型非常方便。例如,在我的纸牌游戏中,我将F#中的等级值定义为:

type Rank = uint8

1 个答案:

答案 0 :(得分:21)

标题为The Rust Programming LanguageCreating Type Synonyms with Type Aliases部分:

Rust提供了声明类型别名的功能,以便为现有类型提供另一个名称。为此,我们使用type关键字。例如,我们可以创建别名Kilometersi32,如下所示:

type Kilometers = i32;

现在,别名Kilometersi32的同义词; [...],Kilometers不是一个单独的新类型。具有Kilometers类型的值将被视为与i32类型的值相同:

type Kilometers = i32;

let x: i32 = 5;
let y: Kilometers = 5;

println!("x + y = {}", x + y);

还有更多你应该阅读,但这回答了这个问题。

作为一篇社论,我不认为类型别名非常适合人们使用它们的很多地方。假设您的Rank类型代表与一副纸牌有关,我建议使用enumnewtype。原因是使用类型别名可以执行以下操作:

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> {
    // ..
}