rust基础

23 阅读7分钟

image.png

1. 赋值语句

let


fn main() { 
let a: u32 = 1;
}

2.数字类型

整数

image.png

浮点数

浮点数有两种类型:f32和f64,分别代表32位浮点数类型和64位浮点数类型。它们也可以跟在字面量的后面,用来指定浮点数值的类型,比如 let a = 10.0f32; 就定义了一个变量a,初始化成32位浮点数类型,值为10.0。

3. 布尔类型

true 和 false。

let a = true; let 
b: bool = false;

4.字符

Rust中的字符类型是 char,值用单引号括起来。

fn main() { 
let c = 'z';
let z: char = 'ℤ'; 
let heart_eyed_cat = '?';
let t = '中';
}

Rust的 char 类型存的是Unicode 散列值,char类型在内存中总是占用 4 个字节大小

5.字符串

Rust中的字符串类型是 String,String内部存储的是Unicode字符串的UTF8编码

let hello = String::from("السلام عليكم"); 
let hello = String::from("Dobrý den"); 
let hello = String::from("Hello"); 
let hello = String::from("שָׁלוֹם"); 
let hello = String::from("नमस्ते"); 
let hello = String::from("こんにちは"); 
let hello = String::from("안녕하세요"); 
let hello = String::from("你好");

字符串字面量中的转义


fn main() { 
// 将""号进行转义 
let byte_escape = "I'm saying \"Hello\""; 
println!("{}", byte_escape); 
// 分两行打印 
let byte_escape = "I'm saying \n 你好"; 
println!("{}", byte_escape); 
// Windows下的换行符 
let byte_escape = "I'm saying \r\n 你好"; 
println!("{}", byte_escape); 
// 打印出 \ 本身 
let byte_escape = "I'm saying \\ Ok"; 
println!("{}", byte_escape); 
// 强行在字符串后面加个0,与C语言的字符串一致。 
let byte_escape = "I'm saying hello.\0"; 
println!("{}", byte_escape); }

6.数组

Rust中的数组是array类型,用于存储同一类型的多个值。数组表示成[T; N],由中括号括起来,中间用分号隔开,分号前面表示类型,分号后面表示数组长度。

fn main() { 
let a: [i32; 5] = [1, 2, 3, 4, 5]; 
let a = [1, 2, 3, 4, 5]; 
}

7.动态数组

Rust中的动态数组类型是Vec(Vector),也就是向量,中文翻译成动态数组。它用来存储同一类型的多个值,容量可在程序运行的过程中动态地扩大或缩小,因此叫做动态数组。

fn main() { 
let v: Vec<i32> = Vec::new(); 
let v = vec![1, 2, 3]; 
let mut v = Vec::new(); 
v.push(5); v.push(6); 
v.push(7); v.push(8); 
}

8.哈希表

哈希表是一种常见的结构,用于存储Key-Value映射关系,基本在各种语言中都有内置提供。Rust中的哈希表类型为HashMap。对一个HashMap结构来说,Key要求是同一种类型,比如是字符串就统一用字符串,是数字就统一用数字。Value也是一样,要求是同一种类型。Key和Value的类型不需要相同

fn main() { 
use std::collections::HashMap; 
let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); 
}

复合类型

9.元组

元组是一个固定(元素)长度的列表,每个元素类型可以不一样。用小括号括起来,元素之间用逗号隔开。例如:

fn main() { 

let tup: (i32, f64, u8) = (500, 6.4, 1);
// 元组使用.运算符访问其元素,下标从0开始,注意语法 
let five_hundred = x.0; 
let six_point_four = x.1; 
let one = x.2;

}

数组的相同点是,它们都是固定元素个数的,在运行时不可伸缩。与数组的不同点是,元组的每个元素的类型可以不一样。元组在Rust中很有用,因为它可以用于函数的返回值,相当于把多个想返回的值捆绑在一起,一次性返回。

当没有任何元素的时候,元组退化成 (),就叫做unit类型,是Rust中一个非常重要的基础类型和值,unit类型唯一的值实例就是(),与其类型本身的表示相同。比如一个函数没有返回值的时候,它实际默认返回的是这个unit值。

10.结构体

Rust中使用 struct 关键字来定义结构体,每个字段的类型可以不一样

struct User {
    active: bool,
    username: String,
    email: String,
    age: u64,
}

fn main() { 
let user1 = User { 
active: true, 
username: String::from("someusername123"), 
email: String::from("someone@example.com"), 
age: 1, 
  }; 
}


11.枚举

Rust中使用 enum 关键字定义枚举类型。比如:

enum IpAddrKind { 
V4, 
V6,
}

枚举类型里面的选项叫做此枚举的变体(variants)。

let four = IpAddrKind::V4; 
let six = IpAddrKind::V6;

以看到,枚举类型也是一种复合类型。但是与结构体不同,结构体类型是里面的所有字段(所有类型)同时起作用,来产生一个具体的实例,而枚举类型是其中的一个变体起作用,来产生一个具体实例,这点区别可以细细品味。学术上,通常把枚举叫作和类型(sum type),把结构体叫作积类型(product type)。

控制流

12.分支语句

Rust中使用if else来构造分支。

fn main() {
    let number = 6;
    // 判断数字number能被4,3,2中的哪一个数字整除
    if number % 4 == 0 {
        println!("number is divisible by 4");
    } else if number % 3 == 0 {
        println!("number is divisible by 3");
    } else if number % 2 == 0 {
        println!("number is divisible by 2");
    } else {
        println!("number is not divisible by 4, 3, or 2");
    }
    
    let x = 1; 
    // 在这里,if else 返回了值 
    let y = if x == 0 {
    // 代码块结尾最后一句不加分号,表示把值返回回去
    100 
    } else {
    // 代码块结尾最后一句不加分号,表示把值返回回去 
    101
    };
    println!("y is {}", y);
    
}


13. 循环语句

Rust中有三种循环语句,分别是loop、while、for。

- loop用于无条件(无限)循环。

fn main() {
    let mut counter = 0;
    
    // 这里,接收从循环体中返回的值,对result进行初始化
    let result = loop {
        counter += 1;
        if counter == 10 {
            // 使用break跳出循环,同时带一个返回值回去
            break counter * 2;
        }
    };

    println!("The result is {result}");
}

while循环为条件判断循环。

fn main() {
    let mut number = 3;

    while number != 0 {
        println!("{number}!");

        number -= 1;
    }

    println!("LIFTOFF!!!");
}


for循环在Rust中,基本上只用于迭代器(暂时可以想象成对数组,动态数组等)的遍历

fn main() {
    let a = [10, 20, 30, 40, 50];

    for element in a {
        println!("the value is: {element}");
    }
}
// 左闭右开区间 
for number in 1..4 { 
println!("{number}");
} 
println!("--"); 
// 左闭右闭区间 
for number in 1..=4 { 
println!("{number}");
} 
println!("--"); 
// 反向 
for number in (1..4).rev() {
println!("{number}"); 
}

14.函数

使用 fn 关键字来定义一个函数

fn print_a_b(a: i32, b: char) {
    println!("The value of a b is: {a}{b}");
}

fn main() {
    print_a_b(5, 'h');
}

15. 闭包(Closure)

闭包是另一种风格的函数。它使用两个竖线符号 || 定义,而不是用 fn () 来定义


// 标准的函数定义
fn  add_one_v1   (x: u32) -> u32 { x + 1 }
// 闭包的定义,请注意形式对比
let add_one_v2 = |x: u32| -> u32 { x + 1 };
// 闭包的定义2,省略了类型标注
let add_one_v3 = |x|             { x + 1 };
// 闭包的定义3,花括号也省略了
let add_one_v4 = |x|               x + 1  ;


fn main() {
    let a = 10u32;             // 局部变量
    
    fn  add_v1   (x: u32) -> u32 { x + a }    // 定义一个内部函数
    let add_v2 = |x: u32| -> u32 { x + a };   // 定义一个闭包
    
    let result1 = add_v1(20);  // 调用函数 
    let result2 = add_v2(20);  // 调用闭包
    println!("{}", result2);
}


add_v1 (内部函数) 报错原因

代码中 fn add_v1 虽然定义在 main 内部,但它本质上还是一个普通的函数。

  • 机制:  Rust 的 fn 定义的函数(包括内部函数)是无状态的。它在编译时就是一个独立的指令块,不包含任何指向“定义它的环境”的指针。
  • 限制:  它只能访问通过参数传入的变量或者全局静态变量(static/const
  • 现状:  变量 a 是 main 函数栈上的一个局部变量。add_v1 无法“看到”或“捕获”这个局部变量 a
  • 编译器报错:  编译器会提示 can't capture dynamic environment in a fn item(在 fn 项中无法捕获动态环境)。