Type Operators 类型运算符
本章节会对三种特殊的运算符进行介绍:as、is 和 impl。
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实现了TestTrait,z将会是是一个特殊的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;
}