内置类型列表:
- 原生类型(primitive types):
- 布尔型(Boolean) — true 或 false
- 数字类(Numeric) — 整型(integer) 和 浮点型(float)
- 文本类(Textual) — 字符型(char) 和 字符串切片(str)
- never类型 — ! 没有值的类型
- 序列类型(sequence types):
- 元组(Tuple)
- 数组(Array)
- 切片(Slice)
- 用户自定义类型(user-defined types):
- 结构体(Struct)
- 枚举(Enum)
- 联合体(Union)
- 函数类型(function types):
- 函数(Functions)
- 闭包(Closures)
- 指针类型(pointer types):
- 引用(References)
- 裸指针(Raw pointers)
- 函数指针(Function pointers)
- trait类型(Trait types):
- trait对象(Trait objects)
- 实现trait(Impl trait)
一、布尔类型
bool
布尔类型的长度为1个字节。
二、数字类型
1.整数
长度 | 有符号类型 | 无符号类型 |
---|---|---|
8位 | i8 | u8 |
16位 | i16 | u16 |
32位 | i32 | u32 |
64位 | i64 | u64 |
128位 | i128 | u128 |
视运行的cpu而定 | isize | usize |
isize 和 usize 类型取决于程序运行的CPU宽度: 若CPU是32位的,则这两个类型是32位的,若CPU是64位,那么它们则是64位。
2.浮点数
f32 32位
f64 64位
默认浮点类型是f64,在现代的CPU中它的速度与f32几乎相同,但精度更高。
三、文本类型
1.字符类型
char
4个字节,值是字符的Unicode码。取值范围为0x0000~0xD7FF
或0xE000~0x10FFFF
。
2.字符串
str
str类型的值的表示方法与 [u8] 相同。但是,Rust标准库对 str 做了额外的限定:str的方法会假定数据是有效的UTF-8。
由于 str 是一个动态大小类型,所以只能使用它的指针类型,比如&str。
四、never类型
用!表示
never类型是一个没有值的类型。一些根本无返回值的情况,比如崩溃、break、continue等行为
!类型的表达式可以自动转换为任何其他类型。
在函数从不返回的时候充当返回值。例如:
fn bar() -> ! {
// --snip--
}
这读 “函数bar从不返回”,而从不返回的函数被称为 发散函数(diverging functions)。不能创建 ! 类型的值,所以bar也不可能返回值。
不过一个不能创建值的类型有什么用呢?
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => panic!(),
};
match要求所有分支必须是相同类型的,为什么这里允许一个分支返回u32而另一个分支却是panic!()呢?因为panic!()的类型是 !,可以自动转换成u32。
五、元组
由多个不同类型组合成一个类型
TupleType :
( )
| ( ( Type , )+ Type? )
元组类型的语法规则为一对圆括号封闭的逗号分割的类型有序列表。一元元组的元素类型后面需要有一个逗号。
元组类型的元素也叫字段。
字段数是类型列表的长度。字段的数量决定元组的元数。有n个字段的元组叫做n元元组。例如,有两个字段的元组就是二元元组。
元组有着固定的长度。一旦定义,就不能再增长或缩小。
元组的字段用它在列表中的位置序号来索引。第一个字段索引为0。第二个字段索引为1。然后以此类推。
不带元素的元组类型(),称为单元类型(unit type)。它的值称为单元值。
元组类型的值是使用元组表达式来构造的。如果一个表达式没有其他有意义的值,那么将返回单元值。
元组类型的示例:
()
(f64, f64)
(String, i32)
(i32, String)
(i32, f64, Vec<String>, Option<bool>)
六、数组
ArrayType :
[ Type ; Expression ]
数组是N个类型为T的元素组成的固定长度的序列,
数组类型写为 [T; N]。
长度是一个计算结果为 usize 的常量表达式。
示例:
let array: [i32; 3] = [1, 2, 3];// 一个栈分配的数组
数组的所有元素总是初始化过的,使用Rust中的安全方法或操作符来访问数组时总是会先做越界检查。
七、切片(Slice)
切片就是数组片段
SliceType :
[ Type ]
切片是一种动态大小类型。切片的大小是运行时才可知的,并不是数组那种编译时就必须确定的。
切片类型写为 [T]。但要使用切片类型时,必须使用它的指针类型,例如:
&[T],共享切片(‘shared slice’),常直接称为切片(slice),它不拥有它指向的数据,只是借用。
&mut [T],可变切片(‘mutable slice’),可变借用它指向的数据。
示例:
let slice: &[i32] = &boxed_array[..];// 数组上的切片
切片的所有元素总是初始化过的,使用Rust中的安全方法或操作符来访问切片时总是会做越界检查。
八、结构体
结构体是一种自定义的数据类型,它可以将多个不同类型组合在一起形成一个新的类型。这些其他类型称为结构体类型的字段
结构体的实例可以用结构体表达式来构造。
结构体的字段可以由可见性修饰符限定,以允许从模块之外来访问结构体中的数据。
元组结构体类型与结构体类型类似,只是字段是匿名的。
单元结构体类型类似于结构体类型,只是它没有字段。
结构体与元组的区别是结构体的每个字段和其本身都有一个名字,这样访问字段的时候就不用记住下标了。
九、枚举
枚举是一种自定义的数据类型,它可以表示多个可能的值。
十、联合体
联合体类型是一种类似C语言里的union的类型,具体的类型名称由联合体项的名称表示。
声明联合体和声明结构体的语法一样,除了用 union 代替 struct外
十一、函数
当引用函数时,会产生函数类型的值。
例子
fn foo<T>() { }
let x = &mut foo::<i32>;
*x = foo::<u32>; // 错误:类型不匹配
函数类型到函数指针的自动强转
// 这里 `foo_ptr_1` 标注使用了 `fn()` 这个函数指针类型。
let foo_ptr_1: fn() = foo::<i32>;
// ... `foo_ptr_2` 类型自动推断。
let foo_ptr_2 = if want_i32 {
foo::<i32>
} else {
foo::<u32>
};
十二、闭包
闭包类型相当于包含捕获变量的结构体。
比如以下闭包示例:
fn f<F: FnOnce() -> String> (g: F) {
println!("{}", g());
}
let mut s = String::from("foo");
let t = String::from("bar");
f(|| {
s += &t;
s
});
// 打印 "foobar".
生成大致如下所示的闭包类型:
struct Closure<'a> {
s : String,
t : &'a String,
}
impl<'a> FnOnce<()> for Closure<'a> {
type Output = String;
fn call_once(self) -> String {
self.s += &*self.t;
self.s
}
}
所以调用f相当于:
f(Closure{s: s, t: &t});
十三、引用
Rust中所有的指针都是显式的头等(first-class)值。 它们可以被移动或复制,存储到其他数据结构中,或从函数中返回。
ReferenceType :
& Lifetime? mut? TypeNoBounds
共享引用(&)
共享引用(&)指向由其他值拥有的内存。不可更改其值。对一个值的共享引用的次数没有限制。
共享引用类型被写为 &type;当需要指定显式的生存期时可写为 &'a type。
可变引用(&mut)
可变引用(&mut)也指向其他值所拥有的内存。可更改其值。对一个值只能有一个可变引用。
可变引用类型被写为 &mut type或 &'a mut type。
十四、裸指针
RawPointerType :
* ( mut | const ) TypeNoBounds
裸指针是没有安全性保证的指针。
裸指针写为 *const T或 *mut T
,例如,*const i32
表示指向32-bit有符号整数的裸指针。拷贝或销毁裸指针对任何其他值的生命期都没有影响。对 裸指针的解引用是非安全操作,可以通过重新借用裸指针(&* 或 &mut *
)将其转换为引用。
在Rust代码中不鼓励使用裸指针;它们是为了提升与外部代码的互操作性,以及编写对性能要求很高的函数或很底层的函数。
在比较裸指针时,比较的是它们的地址,而不是它们指向的数据。当比较裸指针和动态尺寸类型时,还会比较它们指针上的附加/元数据。
可以直接使用 core::ptr::addr_of! 创建 *const类型的裸指针,通过 core::ptr::addr_of_mut! 创建 *mut类型的裸指针。
十五、函数指针
BareFunctionType :
ForLifetimes? unsafe? (extern Abi?)? fn( FunctionParametersMaybeNamedVariadic? ) -> TypeNoBounds?
函数指针类型指向那些在编译时不必知道名字的函数。它们也可以由函数类型或非捕获闭包经过自动强转而来。
非安全(unsafe)限定符表示类型的值是一个非安全函数,而外部(extern)限定符表示它是一个外部函数。
示例
fn add(x: i32, y: i32) -> i32 {
x + y
}
let mut x = add(5,7);
type Binop = fn(i32, i32) -> i32; //Binop为函数指针类型:
let bo: Binop = add;
x = bo(5,7);
十六、trait对象
TraitObjectType :
dyn? TypeParamBounds
TraitObjectTypeOneBound :
dyn? TraitBound
trait对象是关键字dyn后跟一组trait约束。
trait对象是动态尺寸类型。像所有的 DST 一样,trait对象常被用在某种类型的指针后面;例如 &dyn SomeTrait
或Box<dyn SomeTrait>
。
例子:
trait Printable {
fn stringify(&self) -> String;
}
impl Printable for i32 {
fn stringify(&self) -> String { self.to_string() }
}
impl Printable for f32 {
fn stringify(&self) -> String { self.to_string() }
}
fn print(a: Box<dyn Printable>) {
println!("{}", a.stringify());
}
fn main() {
print(Box::new(10));
print(Box::new(10.0));
}
十七、实现trait
ImplTraitType : impl TypeParamBounds
ImplTraitTypeOneBound : impl TraitBound
impl后跟一组trait约束
trait作为函数参数类型
trait Trait {}
fn foo(arg: impl Trait) {}
trait作为函数返回值类型
fn bar() -> impl Trait {}
十八、自动推断型类型
InferredType : _
编译器自动推断出实际使用类型。它只用于泛型参数中:
let x: Vec<_> = (0..10).collect();