Rust 语法笔记

变量绑定(声明变量)

let 变量名: 类型 = 变量值;
let 变量名 = 变量值[类型];
// 整型 默认 i32;浮点 默认 f64

所有的 let 绑定都必须尾接;,代码块也不例外。

mut

可以通过重新声明的方式来改变变量类型
可以下划线改善数字的可读性

声明常量
const / static
除了string字面量,其他类型的 static 必须显示声明类型 &'static str


原生类型 primitives

标量类型 scalar type

* 有符号整数(signed integers)

i8i16i32i64i128isize(指针宽度)

* 无符号整数(unsigned integers)

u8u16u32u64u128usize(指针宽度)

* 浮点数(floating point)

f32f64

* 字符(char)

char 单个 Unicode 字符,如 ‘a’,‘α’ 和 ‘∞’(每个都是 4 字节)

* 布尔型(bool)

bool 只能是 truefalse

* 单元类型(unit type)

()。其唯一可能的值就是 () 这个空元组

尽管单元类型的值是个元组,它却并不被认为是复合类型,因为并不包含多个值。

复合类型 compound type

数组(array)

如 [1, 2, 3]

类型标记 [类型; 长度]

切片 slice
长度不定
类型标记 &[T]
slice 可以用来借用数组的一部分

slice[0]
slice.len()

数组可以自动被借用成为 slice &数组名

元组(tuple)

如 (1, true)
元组可以解构赋值

let foo = Foo { x: (1, 2), y: 3 };
let Foo { x: (a, b), y } = foo;

可以通过下标访问 元组名.0

单个元素的元组需要补一个逗号, 与带括号的字面量区分开

元组可以嵌套

函数可以使用元组来返回多个值

自定义类型

结构体 struct

  • 元组结构体 相当于 具名元组
  • C 语言风格结构体
struct 结构名 {
    属性名1: 类型,
    属性名2: 类型,
}
  • 单元结构体(unit struct)
    不带字段,在泛型中很有用

.. 解构结构体只会添加还没有设置的元素

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

enum WebEvent {
    // 一个 `enum` 可以是单元结构体(称为 `unit-like` 或 `unit`),
    PageLoad,
    PageUnload,
    // 或者一个元组结构体,
    KeyPress(char),
    Paste(String),
    // 或者一个普通的结构体。
    Click { x: i64, y: i64 }
}

访问枚举值

// 方法一:
WebEvent::PageLoad

// 方法二:
use WebEvent::{PageLoad};
// or
// use WebEvent::*;
let xxx = PageLoad; // 等价于 WebEvent::PageLoad

分支判断枚举

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开始
显示赋值

enum Color {
    Red = 0xff0000,
    Green = 0x00ff00,
    Blue = 0x0000ff,
}

使用时可进行类型转化来访问值

Color::Red as i32

enum 的一个常见用法就是创建链表


类型系统

类型转换

Rust 不提供原生类型之间的隐式类型转换

通过 as 显示的类型转化

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 对类型进行别名。
但必须采用大驼峰的命名方式

type Inch = u64;

可以使用 #[allow(non_camel_case_types)] 屏蔽此规则

类型转化方法

最一般的转换会用到 From 和 Into 两个 trait。

From 与 Into

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的类型也不需要注明

let int = 5;
let num: Number = int.into();

TryFrom 与 TryInto

use std::convert::TryFrom;
use std::convert::TryInto;

TryFrom 和 TryInto trait 用于易出错的转换,也正因如此,其返回值是 Result 型。

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()

let result: Result<EvenNumber, ()> = EvenNumber::try_from(8)
let result: Result<EvenNumber, ()> = 8i32.try_into();

ToString 与 FromStr

实现 fmt::Display trait,它会自动提供 ToString

调用 ToString

circle.to_string()
use std::string::ToString;
impl ToString for Circle {
    fn to_string(&self) -> String {
        format!("Circle of radius {:?}", self.radius)
    }
}

只要对目标类型实现了 FromStr trait,就可以用 parse 把字符串转换成目标类型。

// 两种提供类型的方式
let parsed: i32 = "5".parse().unwrap();
let turbo_parsed = "10".parse::<i32>().unwrap();

表达式

代码块也是表达式,所以它们可以用作赋值中的值。

代码块中实际执行的 最后一个表达式 将作为代码块的返回
注意:不要加分号。加了分号就是普通语句,最会代码块中就没有执行的表达式,因而会返回()

流程控制

if/else

条件不需要用括号包裹

if n < 0 {
    print!("{} is negative", n);
} else if n > 0 {
    print!("{} is positive", n);
} else {
    print!("{} is zero", n);
}

if else 本质上也是代码块,因此也可以用于赋值

loop

loop 无限循环

loop {
	···
    if 条件 {
        // 跳过这次迭代的剩下内容
        continue;
    }
    if 条件 {
        // 退出循环
        break;
    }
}

循环设置标签
continue、break 可以通过标签 直接影响外层循环

'outer: loop {
	'inner: loop {
		break 'outer;
	}
}

可以通过break 表达式; 为 loop 设置返回值。

用途:尝试一个操作直到成功为止

while

while 条件 {
}

for

使用区间标记 a..b 可以创建一个迭代器
a..=b 包含b

for n in 1..101 {
}

for 循环默认会使用 into_iter 函数

for name in names.iter()
for name in names.into_iter()
for name in names.iter_mut()

迭代器的方法 into_iteriter iter_mut
iter - 在每次迭代中借用集合中的一个元素。这样集合本身不会被改变,循环之后仍可以使用。
into_iter - 会消耗集合。在每次迭代中,集合中的数据本身会被提供。一旦集合被消耗了,之后就无法再使用了,因为它已经在循环中被 “移除”(move)了。
iter_mut - 可变地(mutably)借用集合中的每个元素,从而允许集合被就地修改。

match

match 会检查匹配覆盖

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 解构方式

解构元组

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条件判断

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 中,若间接地访问一个变量,则不经过重新绑定就无法在分支中再使用它。
@ 符号 用来绑定变量到名称

match age {
  n @ 1  ..= 12 => println!("I'm a child of age {:?}", n),
}

if let

判断let是否绑定成功

// 若 `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 提前返回

fn 函数名(参数: 类型, ···) -> 返回类型 () {
	···
	[return xxx]
}

方法

依附于对象的函数

方法在 impl 代码块中定义。
通过关键字 self 来访问对象中的数据和其他。

selfself: Self 的语法糖(sugar)其中 Self 是方法调用者的类型。
&selfself: &Self 的语法糖
&mut selfself: &mut Self

self: 会消耗本身
&self: 引用 self
&mut self: 可变引用 self
加入到方法的参数中

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 闭包 closure 也叫做 拉姆达表达式 lambda

它们的语法和能力使它们在临时(on the fly)使用时相当方便。

  • 声明时使用 || 替代 () 将输入参数括起来。
  • 函数体定界符({})对于单个表达式是可选的。
  • 有能力捕获外部环境的变量。
|i: i32| -> i32 { i + 1 };
|i     |          i + 1  ;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值