Rust快速入门

发布于: 2021-11-17T15:10:20+08:00
更新于: 2021-11-17T15:10:20+08:00
作者: Stiller

类别: Rust.

标签:Rust Linux

Rust是一门新式的优秀的语言,这门语言一般用于替代C、C++进行硬件层面的开发或者是一些系统后台的开发,本文是Rust的快速入门。

Rust的安装

Windows可以直接下载应用安装程序

如果是WIndows Linux 子系统,需要使用curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

安装过程缓慢,安装完成后,可以使用rustc进行测试。

  • Rust安装需要安装C++ build tool,如果在Windows中需要安装VS或者是单独安装VC++ build tool

使用cargo new helloWorld创建HelloWorld程序

fn main() {

  println!("Hello, world!");

}

其中fn是定义了一个函数,但是println!()是一个宏而不是一个函数,调用宏需要使用"!"

使用下方的命令進行编译,需要进入到项目文件夹中:

cargo build

编译如果没有出现问题的话会在target文件夹中生成一个编译后的结果,可以直接运行./target/debug/helloworld.exe

Rust的变量和常量

变量:

Rust虽然是一个静态类型(编译时就明确类型)强类型的语言,但是并不需要将变量进行显式的声明,而是直接可以使用下方的形式

let _x = 1

在Rust中会自动的识别这个变量的类型为int32,但是此时这个变量是一个不可变变量

fn main() {
    let _x =1;
}

对于变量的输出则是采用println!("{}",x)使用大括号的形式进行数据的输出和打印

不可变变量对于Rust下方代码是不可运行的。

fn main() {
    let _x =1;
    _x=2;
}

如果需要进行变量的常规变更,例如计数器这样的操作,需要使用下方的代码。在Rust中强制要求所有的默认变量都是不可以被二次赋值的,这也保证了Rust的安全和优势,同时在很多编译器语言中,SSA(静态单赋值)不允许二次变量值的变动,每次变量用完即丢。

fn main() {
    let  mut _x = 1;
    _x = 2;
    print!("{}", _x)
}
常量:

编译期就会进行计算,使用const 进行修饰

常量在Rust中存在以下特征:1. 不允许可变动(不能使用mut修饰)2. 任何地方都可以进行变量的声明 3. 常量只能设置为常量表达式

const _X: i32 = 1;
fn main() {
    println!("{}", _X);
}
基本数据类型:

无符号整数:u8,u16……u64,usize(计算机系统有关)

有符号整数: i8, i16, i32,isize(计算机系统有关)

浮点数:f32、f64(速度大致相同)

布尔值(bool):一个字节:true、false

字符(char):Char是Unicode,大小4bytes大小(单引号)字符串(双引号)

数组:固定长度[],默认为长度一定的i32

fn main() {
    let array: [i32; 5] = [1, 2, 3, 4, 5];
    println!("{}", array[1]);
}
流程控制:
  1. if:Rust中条件判定只能是布尔值

rust fn main() { let number = 3; if number < 5 { println!("condition was true"); } else { println!("condition was false"); } }

可以仿照三元表达式

rust let number = 3; //在Rust中Expression可以有返回值 (c 中statement只是标识状态,没有返回值) let target = if number < 5 { 4 } else { 6 };//两个结果需要是统一的类型,因为Rust在编译时间就会确认变量的类型 println!("{}", target);

  1. loop:

  2. 不显示的退出一直运行

  3. ```rust

    fn main() { let mut number = 3; loop { number += 1; println!("{}", number); if number == 10 { break; } } println!("loop ended"); } ```

  4. while:

rust fn main() { let mut number = 3; while number<10 { number += 1; println!("{}", number); } }

  1. for

rust fn main() { let a = [1, 2, 3, 4, 5]; for u in a.iter() { println!("{}", u); } }

#### 结构体:

rust struct User{ username: String, age:u32 }

如果需要结构体进行修改,需要使用关键词mut进行修饰

struct User {
    username: String,
    age: i32
}
fn main() {
    let user1 = User {
        username: String::from("John"),
        age: 30,
    };
    print!("{}",user1.username)
}

使用impl语法糖可以模拟面向对象的实现,方法的定义。

struct User {
    username: String,
    age: i32
}
impl User {
    fn print_user(&self) {
        println!("{} is {}", self.username, self.age);
    }
}

fn main() {
    let user1 = User {
        username: String::from("John"),
        age: 30,
    };
    user1.print_user()
}

泛型:

//std::cmp::PartialOrd 这个是类型的约束,可以比较大小
fn larger<T: std::cmp::PartialOrd>(a: T, b: T) -> T {
    if a > b {
        a
    } else {
        b
    }
}

fn main() {
    let number1 = 3;
    let number2 = 4;
    let max = larger(number1, number2);
    println!("The largest number is {}", max);
}

Rust采用两个通用的枚举来完成错误处理和空返回(有的语言使用Null)为了解决空指针问题

  1. Option 代表有或者无Some(T),None

  2. Result 代表成功或者失败Ok(T),Err(E)

需要使用匹配语法进行条件的判定

fn main() {
    match std::env::home_dir() {
        Some(data) => println!("option is some,data={:?}", data),
        None => print!("option is none"),
    }
    match std::env::var("PATH") {
        Ok(data) => print!("home env,data={}", data),
        Err(err)=>print!("error is {}",err)
    }
}

Rust中的内存管理(所有权)

C: 手动管理(malloc和free)

GC:Go、Java

Rust:基于生命周期的半自动管理(所有权和生命周期)

在Rust中所有的变量只拥有唯一的所有者,所以下方的代码是不能运行的,因为string1被赋值给了string2,所以不能打印string1,因为已经转移到了string2

fn main() {
    //存储在堆中
    let string1=String::from("hello world");
    //直接将string1的指向归属给了string2,而不是在堆中复制值
    let string2=string1;
    println!("{}",string1);
}
  1. 当离开了作用域后{}花括号决定的作用域,会被销毁

引用与借用

fn string_resver(s: String)->String {
    s.chars().rev().collect()
}
fn main() {
    let string1 = String::from("hello world");
    let string2 = string_resver(string1);
    println!("{}", string1);
    println!("{}", string2);
}

上述代码是错误的代码,因为string1的所有权已经转移到了string_resver函数中,所以生命周期已经被销毁,所以需要使用到原变量的值,需要使用下方的代码。

fn string_resver(s: String)->(String,String){
   (s.clone(), s.chars().rev().collect())
}
fn main() {
    let string1 = String::from("hello world");
    let (string3,string2) = string_resver(string1);
    println!("{}", string3);
    println!("{}", string2);
}

所以可以直接通过传递引用的方式进行参数的传递

fn string_resver(s: &String) -> String {
    s.chars().rev().collect()
}
fn main() {
    let string1 = String::from("hello world");
    let string2 = string_resver(&string1);
    println!("{}", string1);
    println!("{}", string2);
}
1. 引用不会获取到数据的所有权
2. 默认情况下引用是不可变的
3. 同一时间最多只能存在一个可变引用多线程中避免数据竞争
fn string_resver(s: &mut String) {
    s.push_str("!");
}
fn main() {
    let mut string1 = String::from("hello world");
    string_resver(&mut string1);
    println!("{}", string1);
}

RefCell用来实现内部可变性,internal mutability,即数据可以在自身的方法中改变自身,但对外是不可变的。

Box, Rc, RefCell比较:

Rc,允许多重拥有,不可变借用,编译时检查

Box,单一拥有者,可变或不可变借用,编译时检查(Deref, DerefMut)

RefCell, 单一拥有者,可变或不可变借用,运行时检查。可变不可变是对外的,都可以在内部改变。其实是把不安全的操作包装在安全的接口中

链接