Type Operators 类型运算符

本章节会对三种特殊的运算符进行介绍:asisimpl

as 类型转换运算符

as 运算符用于将一个值转换为另一个类型。

基础类型转换

在转换一些基础类型的时候(比如int类型之间的转换),as 运算符是不会失败的,例如:

let a: i64 = 1;
let b: i32 = a as i32;

在这个例子中,a 是一个 i64 类型的变量,我们将其转换为 i32 类型的变量 b。这种转换永远成功,尽管可能会导致精度丢失或者损失一部分数据。

和类型转换

as也可以进行对和类型的转换,假设我们有如下类型:

struct ST{};
type Test<T> = T | ST;

我们可以将任意一个类型用as转换为Option类型:

let a: i64 = 1;
let b = a as Test<i64>;

将子类型转换为和类型是不可能失败的。如果尝试转化为一个不可能的类型,编译器会报错。

反之,as运算符也可以将和类型转换为子类型:

let a: i64 = 1;
let b = a as Test<i64>;
let c: i64 = b as i64!;
let d: Option<i64> = b as i64?;

但是,将和类型转换为子类型可能会失败,编译器不会允许你直接使用常规的as语句进行转换,你必须使用?!来标注转换是非强制的还是强制的。

如果使用?标注,那么x as T?语句会返回一个Option<T>类型,如果转换失败,则该返回值是None

如果使用!标注,那么x as T!语句会返回一个T类型,如果转换失败,则会导致运行时错误(__cast_panic)。

泛型类型转换

as运算符也可以用于泛型类型的转换:

fn test<T>(x: T) i64 {
    let y = x as i64!;
    return x;
}

如果泛型类型转换失败,会导致运行时错误(__cast_panic)。这种转换是编译期进行的,没有运行时开销。

泛型的转换一定是强制的,需要带上!标注。

if let ... as ... 语法

if let ... as ... 语法可以用于安全的对泛型类型进行转换:

fn test<T>(x: T) i64 {
    if let y = x as i64 {
        return y;
    }
    return -1;
}

is 类型判断运算符

基础类型判断

is 运算符用于判断一个值是否是某个类型。例如:

let a: i64 = 1;
let b = a is i64;

在这个例子中,b 的值是 true,因为 a 是一个 i64 类型的变量。

和类型判断

is 运算符也可以用于判断和类型:

let a: i64 = 1;
let b = a as Test<i64>;
let c = b is i64;

在这个例子中,c 的值是 true,因为 b 是一个 i64 类型的变量。

泛型类型判断

特殊的,is 运算符也可以用于判断泛型类型:

fn test<T>(x: T) T {
    if x is i64 {
        doSth();
    }
    return x;
}

impl 判断实现运算符

impl 运算符用于判断一个泛型是否实现了某个trait。例如:

trait TestTrait {
    fn test();
}

struct TestStruct{};

impl TestTrait for TestStruct {
    fn test() {
        println("test");
    }
}

fn test<T>(x: T) T {
    let y = x impl TestTrait?;
    let z = x impl TestTrait!;
    z.test();
    return x;
}

普通的impl语句必须带上?!标注,否则编译器会报错。

对于?标注,如果泛型类型没有实现trait,那么语句会返回false,否则返回true

对于!标注,如果泛型类型没有实现trait,那么语句会导致运行时错误(__impl_panic)。以上方例子举例,如果x没有实现TestTrait,那么let z = x impl TestTrait!;会导致运行时错误。反之,如果x实现了TestTraitz将会是是一个特殊的T类型,但是他的增加了实现TestTrait的约束,使得下一行代码可以调用TestTraittrait的test方法。请注意,虽然z的类型和x的类型都是T,但是他们的约束是不同的,严格来说并不是同一类型。z的类型T,也不是上下文中的T类型。

if let ... impl ... 语法

if let ... impl ... 语法可以用于安全的对泛型类型进行trait实现判断:

fn test<T>(x: T) T {
    if let y = x impl TestTrait {
        y.test();
    }
    return x;
}

他等同于

fn test<T>(x: T) T {
    if x impl TestTrait? {
        let y = x impl TestTrait!;
        y.test();
    }
    return x;
}