变量绑定(声明变量)
rust
let 变量名: 类型 = 变量值;
let 变量名 = 变量值[类型];
// 整型 默认 i32;浮点 默认 f64
所有的 let
绑定都必须尾接;
,代码块也不例外。
mut
可以通过重新声明的方式来改变变量类型
可以下划线改善数字的可读性
声明常量
const / static
除了string字面量,其他类型的 static 必须显示声明类型 &'static str
原生类型 primitives
标量类型 scalar type
* 有符号整数(signed integers)
i8
、i16
、i32
、i64
、i128
和 isize
(指针宽度)
* 无符号整数(unsigned integers)
u8
、u16
、u32
、u64
、u128
和 usize
(指针宽度)
* 浮点数(floating point)
f32
、f64
* 字符(char)
char
单个 Unicode 字符,如 'a','α' 和 '∞'(每个都是 4 字节)
* 布尔型(bool)
bool
只能是 true 或 false
* 单元类型(unit type)
()
。其唯一可能的值就是 ()
这个空元组
尽管单元类型的值是个元组,它却并不被认为是复合类型,因为并不包含多个值。
复合类型 compound type
数组(array)
如 [1, 2, 3]
类型标记 [类型; 长度]
切片 slice
长度不定
类型标记 &[T]
slice 可以用来借用数组的一部分
rust
slice[0]
slice.len()
数组可以自动被借用成为 slice
&数组名
元组(tuple)
如 (1, true)
元组可以解构赋值
rust
let foo = Foo { x: (1, 2), y: 3 };
let Foo { x: (a, b), y } = foo;
可以通过下标访问 元组名.0
单个元素的元组需要补一个逗号,
与带括号的字面量区分开
元组可以嵌套
函数可以使用元组来返回多个值
自定义类型
结构体 struct
- 元组结构体 相当于 具名元组
- C 语言风格结构体
rust
struct 结构名 {
属性名1: 类型,
属性名2: 类型,
}
- 单元结构体(unit struct)
不带字段,在泛型中很有用
..
解构结构体只会添加还没有设置的元素
rust
let point: Point = Point { x: 10.3, y: 0.4 };
let bottom_right = Point { x: 5.2, ..point };
// (5.2, 0.4)
let Point { x: left_edge, y: top_edge } = point;
// left_edge top_edge 分别取到 x,y 的值
let Pair(integer, decimal) = Pair(1, 0.1);
枚举 enum
rust
enum WebEvent {
// 一个 `enum` 可以是单元结构体(称为 `unit-like` 或 `unit`),
PageLoad,
PageUnload,
// 或者一个元组结构体,
KeyPress(char),
Paste(String),
// 或者一个普通的结构体。
Click { x: i64, y: i64 }
}
访问枚举值
rust
// 方法一:
WebEvent::PageLoad
// 方法二:
use WebEvent::{PageLoad};
// or
// use WebEvent::*;
let xxx = PageLoad; // 等价于 WebEvent::PageLoad
分支判断枚举
rust
match event {
WebEvent::PageLoad => println!("page loaded"),
WebEvent::PageUnload => println!("page unloaded"),
// 从 `enum` 里解构出 `c`。
WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
WebEvent::Paste(s) => println!("pasted \"{}\".", s),
// 把 `Click` 解构给 `x` and `y`。
WebEvent::Click { x, y } => {
println!("clicked at x={}, y={}.", x, y);
},
}
枚举默认值从0开始
显示赋值
rust
enum Color {
Red = 0xff0000,
Green = 0x00ff00,
Blue = 0x0000ff,
}
使用时可进行类型转化来访问值
rust
Color::Red as i32
enum 的一个常见用法就是创建链表
类型系统
类型转换
Rust 不提供原生类型之间的隐式类型转换
通过 as
显示的类型转化
rust
someVar as u32
当把任何类型转换为无符号类型 T 时(数据范围不匹配),会不断加上或减去
(std::T::MAX + 1)
直到值位于新类型 T 的范围内。实际实现是:从最低有效位(LSB,least significant bits)开始保留 8 位,然后剩余位置,直到最高有效位(MSB,most significant bit)都被抛弃。
当把无符号类型转化为等长的有符号类型,最高位为1时标记为负数详情查阅 计算机原理-补码相关内容
#![allow(overflowing_literals)]
不显示类型转换产生的溢出警告。
rust 1.45 以后,将浮点数转化为无符号整数,超出上限 会直接转化为最大值;低于下限 会直接取 0。因为若按上述方法转化会让结果难以预料。
但依然可以使用
.to_int_unchecked::<u8>()
维持原来的转化方式
字面量
可通过后缀方式声明其类型
整数 默认 u32
浮点数 默认 f64
类型推断
可以根据赋予的值,来推断类型
减少显示声明类型
Vec 可以通过传入数据的类型 确定其类型
别名 type
可以使用 type 对类型进行别名。
但必须采用大驼峰的命名方式
rust
type Inch = u64;
可以使用
#[allow(non_camel_case_types)]
屏蔽此规则
类型转化方法
最一般的转换会用到 From 和 Into 两个 trait。
From 与 Into
rust
impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}
let num = Number::from(30);
Into trait 就是把 From trait 倒过来而已
已经写 From 后,便不再需要写 Into 了
同into的类型也不需要注明
rust
let int = 5;
let num: Number = int.into();
TryFrom 与 TryInto
rust
use std::convert::TryFrom;
use std::convert::TryInto;
TryFrom 和 TryInto trait 用于易出错的转换,也正因如此,其返回值是 Result 型。
rust
impl TryFrom<i32> for EvenNumber {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
if value % 2 == 0 {
Ok(EvenNumber(value))
} else {
Err(())
}
}
}
Ok()
Err()
rust
let result: Result<EvenNumber, ()> = EvenNumber::try_from(8)
let result: Result<EvenNumber, ()> = 8i32.try_into();
ToString 与 FromStr
实现 fmt::Display trait
,它会自动提供 ToString
调用 ToString
rust
circle.to_string()
rust
use std::string::ToString;
impl ToString for Circle {
fn to_string(&self) -> String {
format!("Circle of radius {:?}", self.radius)
}
}
只要对目标类型实现了 FromStr trait,就可以用 parse 把字符串转换成目标类型。
rust
// 两种提供类型的方式
let parsed: i32 = "5".parse().unwrap();
let turbo_parsed = "10".parse::<i32>().unwrap();
表达式
代码块也是表达式,所以它们可以用作赋值中的值。
代码块中实际执行的 最后一个表达式 将作为代码块的返回
注意:不要加分号。加了分号就是普通语句,最会代码块中就没有执行的表达式,因而会返回()
流程控制
if/else
条件不需要用括号包裹
rust
if n < 0 {
print!("{} is negative", n);
} else if n > 0 {
print!("{} is positive", n);
} else {
print!("{} is zero", n);
}
if else 本质上也是代码块,因此也可以用于赋值
loop
loop 无限循环
rust
loop {
···
if 条件 {
// 跳过这次迭代的剩下内容
continue;
}
if 条件 {
// 退出循环
break;
}
}
循环设置标签
continue、break 可以通过标签 直接影响外层循环
rust
'outer: loop {
'inner: loop {
break 'outer;
}
}
可以通过break 表达式;
为 loop 设置返回值。
用途:尝试一个操作直到成功为止
while
rust
while 条件 {
}
for
使用区间标记
a..b
可以创建一个迭代器
a..=b
包含b
rust
for n in 1..101 {
}
for 循环默认会使用 into_iter 函数
rust
for name in names.iter()
for name in names.into_iter()
for name in names.iter_mut()
迭代器的方法
into_iter
、iter
、iter_mut
iter - 在每次迭代中借用集合中的一个元素。这样集合本身不会被改变,循环之后仍可以使用。
into_iter - 会消耗集合。在每次迭代中,集合中的数据本身会被提供。一旦集合被消耗了,之后就无法再使用了,因为它已经在循环中被 "移除"(move)了。
iter_mut - 可变地(mutably)借用集合中的每个元素,从而允许集合被就地修改。
match
match 会检查匹配覆盖
rust
match number {
// 匹配单个值
1 => println!("One!"),
// 匹配多个值
2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
// 试一试 ^ 将 13 添加到质数列表中
// 匹配一个闭区间范围
13..=19 => println!("A teen"),
// 处理其他情况
_ => println!("Ain't special"),
}
match 解构方式
解构元组
rust
match triple {
// 解构出第二个和第三个元素
(0, y, z) => println!("First is `0`, `y` is {:?}, and `z` is {:?}", y, z),
// `..` 可用来忽略元组的其余部分
(1, ..) => println!("First is `1` and the rest doesn't matter"),
_ => println!("It doesn't matter what they are"),
}
解构枚举
枚举中的元组也可通过上法解构
解构指针
现在还不懂指针,先跳过???
match 卫语句(guard)
可以加上 match 卫语句(guard) 来过滤分支。
给匹配增加额外的if条件判断
rust
match pair {
// "if x == y" 是一个卫语句
(x, y) if x == y => println!("These are twins"),
(x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
(x, _) if x % 2 == 1 => println!("The first one is odd"),
_ => println!("No correlation..."),
}
match 重新绑定
在 match 中,若间接地访问一个变量,则不经过重新绑定就无法在分支中再使用它。
@ 符号 用来绑定变量到名称
rust
match age {
n @ 1 ..= 12 => println!("I'm a child of age {:?}", n),
}
if let
判断let是否绑定成功
rust
// 若 `let` 将 `number` 解构成 `Some(i)`,则执行
if let Some(i) = number {
println!("Matched {:?}!", i);
}
// 匹配枚举
if let Foo::Bar = b {
println!("b is foobar");
}
直接使用
if Foo::Bar==a
,需要注明#[derive(PartialEq)]
while let
与上类似
可以简化 循环与match的组合代码
函数
默认与代码块的返回逻辑相同
但可以 return
提前返回
rust
fn 函数名(参数: 类型, ···) -> 返回类型 () {
···
[return xxx]
}
方法
依附于对象的函数
方法在 impl 代码块中定义。
通过关键字 self 来访问对象中的数据和其他。
self
为self: Self
的语法糖(sugar)其中Self
是方法调用者的类型。
&self
是self: &Self
的语法糖
&mut self
为self: &mut Self
self: 会消耗本身
&self: 引用 self
&mut self: 可变引用 self
加入到方法的参数中
rust
impl Point {
fn origin() -> Point {
Point { x: 0.0, y: 0.0 }
}
fn new(x: f64, y: f64) -> Point {
Point { x: x, y: y }
}
}
闭包
- 声明时使用
||
替代()
将输入参数括起来。 - 函数体定界符(
{}
)对于单个表达式是可选的。 - 有能力捕获外部环境的变量。
rust
|i: i32| -> i32 { i + 1 };
|i | i + 1 ;