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

type Rank = uint8

推荐答案

来自标题为Creating Type Synonyms with Type AliasesThe Rust Programming Language节:

Rust提供了声明一个type alias来为现有类型命名的能力.为此,我们使用type关键字.例如,我们可以这样创建别名Kilometersi32:

type Kilometers = i32;

现在,别名Kilometersi32的同义词;[...], Kilometers不是一个单独的新类型.类型为i32的值将与类型为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>,但随后认为这会令人困惑.:-)

我使用它们的另一种情况是缩短我不想隐藏的较大类型.这种情况发生在迭代器或Results之类的类型上,可以使用see in the standard library.比如:

type CardResult<T> = Result<T, Error>;

fn foo() -> CardResult<String> {
    // ..
}

Rust相关问答推荐

给定使用newype习语定义的类型上的铁 rust Vec,有没有方法获得底层原始类型的一部分?

使用nom将任何空白、制表符、白线等序列替换为单个空白

当两者都有效时,为什么Rust编译器建议添加';&;而不是';*';?

这种获取-释放关系是如何运作的?

为潜在的下游实现使用泛型绑定而不是没有泛型绑定的trait

如何使用RefCell::JOYMOMTborrow 对 struct 不同字段的可变引用

为什么这个变量不需要是可变的?

不同类型泛型的映射

这个不安全的 Rust 代码有什么问题,所以它可以在 Windows 上运行,但不能在 Ubuntu 上运行?

如何限制 GtkColumnView 行数

Rust LinkedList 中的borrow 判断器错误的原因是什么?

std mpsc 发送者通道在闭包中使用时关闭

std::vector::shrink_to_fit 如何在 Rust 中工作?

仅当函数写为闭包时才会出现生命周期错误

rust tokio::spawn 在 mutexguard 之后等待

为什么 match 语句对引用类型比函数参数更挑剔?

有没有更好的方法来为拥有 DIsplay 事物集合的 struct 实现 Display?

在 Rust 中获得准确时间的正确方法?

覆盖类型的要求到底是什么?为什么单个元素元组满足它?

为什么当borrow 变量发生变化时,borrow 变量不会改变?