|
| 1 | +# Type Operators 类型运算符 |
| 2 | + |
| 3 | +本章节会对三种特殊的运算符进行介绍:`as`、`is` 和 `impl`。 |
| 4 | + |
| 5 | +## `as` 类型转换运算符 |
| 6 | + |
| 7 | +`as` 运算符用于将一个值转换为另一个类型。 |
| 8 | + |
| 9 | +### 基础类型转换 |
| 10 | + |
| 11 | +在转换一些基础类型的时候(比如int类型之间的转换),`as` 运算符是不会失败的,例如: |
| 12 | + |
| 13 | +```plang |
| 14 | +let a: i64 = 1; |
| 15 | +let b: i32 = a as i32; |
| 16 | +``` |
| 17 | + |
| 18 | +在这个例子中,`a` 是一个 `i64` 类型的变量,我们将其转换为 `i32` 类型的变量 `b`。这种转换永远成功,尽管可能会导致精度丢失或者损失一部分数据。 |
| 19 | + |
| 20 | +### 和类型转换 |
| 21 | + |
| 22 | +`as`也可以进行对`和类型`的转换,假设我们有如下类型: |
| 23 | + |
| 24 | +```plang |
| 25 | +struct ST{}; |
| 26 | +type Test<T> = T | ST; |
| 27 | +``` |
| 28 | + |
| 29 | +我们可以将任意一个类型用`as`转换为`Option`类型: |
| 30 | + |
| 31 | +```plang |
| 32 | +let a: i64 = 1; |
| 33 | +let b = a as Test<i64>; |
| 34 | +``` |
| 35 | + |
| 36 | +将子类型转换为和类型是不可能失败的。如果尝试转化为一个不可能的类型,编译器会报错。 |
| 37 | + |
| 38 | +反之,`as`运算符也可以将和类型转换为子类型: |
| 39 | + |
| 40 | +```plang |
| 41 | +let a: i64 = 1; |
| 42 | +let b = a as Test<i64>; |
| 43 | +let c: i64 = b as i64!; |
| 44 | +let d: Option<i64> = b as i64?; |
| 45 | +``` |
| 46 | + |
| 47 | +但是,将和类型转换为子类型可能会失败,编译器不会允许你直接使用常规的`as`语句进行转换,你必须使用`?`或`!`来标注转换是非强制的还是强制的。 |
| 48 | + |
| 49 | +如果使用`?`标注,那么`x as T?`语句会返回一个`Option<T>`类型,如果转换失败,则该返回值是`None`。 |
| 50 | + |
| 51 | +如果使用`!`标注,那么`x as T!`语句会返回一个`T`类型,如果转换失败,则会导致运行时错误(__cast_panic)。 |
| 52 | + |
| 53 | +### 泛型类型转换 |
| 54 | + |
| 55 | +`as`运算符也可以用于泛型类型的转换: |
| 56 | + |
| 57 | +```plang |
| 58 | +fn test<T>(x: T) i64 { |
| 59 | + let y = x as i64!; |
| 60 | + return x; |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +如果泛型类型转换失败,会导致运行时错误(__cast_panic)。这种转换是编译期进行的,没有运行时开销。 |
| 65 | + |
| 66 | +泛型的转换一定是强制的,需要带上`!`标注。 |
| 67 | + |
| 68 | +#### if let ... as ... 语法 |
| 69 | + |
| 70 | +`if let ... as ...` 语法可以用于安全的对泛型类型进行转换: |
| 71 | + |
| 72 | +```plang |
| 73 | +fn test<T>(x: T) i64 { |
| 74 | + if let y = x as i64 { |
| 75 | + return y; |
| 76 | + } |
| 77 | + return -1; |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +## `is` 类型判断运算符 |
| 82 | + |
| 83 | +### 基础类型判断 |
| 84 | + |
| 85 | +`is` 运算符用于判断一个值是否是某个类型。例如: |
| 86 | + |
| 87 | +```plang |
| 88 | +let a: i64 = 1; |
| 89 | +let b = a is i64; |
| 90 | +``` |
| 91 | + |
| 92 | +在这个例子中,`b` 的值是 `true`,因为 `a` 是一个 `i64` 类型的变量。 |
| 93 | + |
| 94 | +### 和类型判断 |
| 95 | + |
| 96 | +`is` 运算符也可以用于判断和类型: |
| 97 | + |
| 98 | +```plang |
| 99 | +let a: i64 = 1; |
| 100 | +let b = a as Test<i64>; |
| 101 | +let c = b is i64; |
| 102 | +``` |
| 103 | + |
| 104 | +在这个例子中,`c` 的值是 `true`,因为 `b` 是一个 `i64` 类型的变量。 |
| 105 | + |
| 106 | +### 泛型类型判断 |
| 107 | + |
| 108 | +特殊的,`is` 运算符也可以用于判断泛型类型: |
| 109 | + |
| 110 | +```plang |
| 111 | +fn test<T>(x: T) T { |
| 112 | + if x is i64 { |
| 113 | + doSth(); |
| 114 | + } |
| 115 | + return x; |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +## `impl` 判断实现运算符 |
| 120 | + |
| 121 | +`impl` 运算符用于判断一个泛型是否实现了某个trait。例如: |
| 122 | + |
| 123 | +```plang |
| 124 | +trait TestTrait { |
| 125 | + fn test(); |
| 126 | +} |
| 127 | +
|
| 128 | +struct TestStruct{}; |
| 129 | +
|
| 130 | +impl TestTrait for TestStruct { |
| 131 | + fn test() { |
| 132 | + println("test"); |
| 133 | + } |
| 134 | +} |
| 135 | +
|
| 136 | +fn test<T>(x: T) T { |
| 137 | + let y = x impl TestTrait?; |
| 138 | + let z = x impl TestTrait!; |
| 139 | + z.test(); |
| 140 | + return x; |
| 141 | +} |
| 142 | +
|
| 143 | +``` |
| 144 | + |
| 145 | +普通的`impl`语句必须带上`?`或`!`标注,否则编译器会报错。 |
| 146 | + |
| 147 | +对于`?`标注,如果泛型类型没有实现trait,那么语句会返回`false`,否则返回`true`。 |
| 148 | + |
| 149 | +对于`!`标注,如果泛型类型没有实现trait,那么语句会导致运行时错误(__impl_panic)。以上方例子举例,如果`x`没有实现`TestTrait`,那么`let z = x impl TestTrait!;`会导致运行时错误。反之,如果`x`实现了`TestTrait`,`z`将会是是一个特殊的`T`类型,但是他的增加了实现`TestTrait`的约束,使得下一行代码可以调用`TestTrait`trait的`test`方法。请注意,虽然`z`的类型和`x`的类型都是`T`,但是他们的约束是不同的,严格来说并不是同一类型。`z`的类型`T`,也不是上下文中的`T`类型。 |
| 150 | + |
| 151 | +### `if let ... impl ...` 语法 |
| 152 | + |
| 153 | +`if let ... impl ...` 语法可以用于安全的对泛型类型进行trait实现判断: |
| 154 | + |
| 155 | +```plang |
| 156 | +fn test<T>(x: T) T { |
| 157 | + if let y = x impl TestTrait { |
| 158 | + y.test(); |
| 159 | + } |
| 160 | + return x; |
| 161 | +} |
| 162 | +``` |
| 163 | + |
| 164 | +他等同于 |
| 165 | + |
| 166 | +```plang |
| 167 | +fn test<T>(x: T) T { |
| 168 | + if x impl TestTrait? { |
| 169 | + let y = x impl TestTrait!; |
| 170 | + y.test(); |
| 171 | + } |
| 172 | + return x; |
| 173 | +} |
| 174 | +
|
| 175 | +``` |
| 176 | + |
| 177 | + |
| 178 | + |
| 179 | + |
| 180 | + |
| 181 | + |
| 182 | + |
| 183 | + |
| 184 | + |
| 185 | + |
| 186 | + |
0 commit comments