当前位置:   article > 正文

Rust开发快速入门_rust开发经验

rust开发经验

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!");

}
  • 1
  • 2
  • 3
  • 4
  • 5

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

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

cargo build

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

Rust的变量和常量

变量:

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

let _x = 1

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

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

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

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

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

  • 1
  • 2
  • 3
  • 4
  • 5

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

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

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

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

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

无符号整数: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
  • 2
  • 3
  • 4
  • 5
流程控制:
  1. if:Rust中条件判定只能是布尔值

       fn main() {
           let number = 3;
           if number < 5 {
               println!("condition was true");
           } else {
               println!("condition was false");
           }
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    可以仿照三元表达式

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

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

    2. 
      fn main() {
          let mut number = 3;
          loop {
              number += 1;
              println!("{}", number);
              if number == 10 {
                  break;
              }
          }
          println!("loop ended");
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
  3. while:

    fn main() {
        let mut number = 3;
        while number<10 {
            number += 1;
            println!("{}", number);        
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  4. for

    fn main() {
        let a = [1, 2, 3, 4, 5];
        for u in a.iter() {
            println!("{}", u);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    结构体:
    struct User{
    	username: String,
        age:u32
    }
    
    • 1
    • 2
    • 3
    • 4

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

struct User {
    username: String,
    age: i32
}
fn main() {
    let user1 = User {
        username: String::from("John"),
        age: 30,
    };
    print!("{}",user1.username)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

使用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()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
泛型:
//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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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

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

  2. Result<T,E> 代表成功或者失败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)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

上述代码是错误的代码,因为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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

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
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
1. 引用不会获取到数据的所有权
2. 默认情况下引用是不可变的
3. 同一时间最多只能存在一个可变引用(多线程中避免数据竞争)
  • 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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

Box, Rc, RefCell比较:

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

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

RefCell, 单一拥有者,可变或不可变借用,运行时检查。可变不可变是对外的,都可以在内部改变。其实是把不安全的操作包装在安全的接口中
Cargo.toml中保存的是项目依赖和项目信息,如果需要使用第三方的模块,则需要在dependencies中增加内容。

[dependencies]
rand = "0.8.3"
  • 1
  • 2

然后使用cargo run命令会自动的进行依赖包的安装和构建。

官方的第一个练习:猜数字,使用到了rand模块

use std::io;
use rand::Rng;
fn main() {
    println!("输入你需要选择的数字!");
    let mut string_input = String::new();
    io::stdin().read_line(&mut string_input).expect("读取失败");
    println!("您输入的数目是{}", string_input);
    let radom_number = rand::thread_rng().gen_range(1..101);
    println!("随机数是{}", radom_number);
    if string_input == radom_number.to_string() {
        println!("恭喜你猜对了!");
    } else {
        println!("很遗憾你猜错了!");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在Rust中需要对比两个不同类型的数据,需要进行显式的类型转换例如.to_string()或者是.parse()需要注意的是,在Rust中推荐的变量命名和函数命名类似于Python,需要进行下划线作为全部小写单词切分,而不是类似于Java,采用小写驼峰形式。

在Rust中存在一些特殊点:

  1. Rust变量可以进行遮蔽,也就是说定义一个x为int,但是可以在后续代码中新建一个变量x为字符,这两者并不是转化关系,而是完全独立
  2. 常量要求必须初始化值和类型,实际上并不一定需要是显示指定
  3. Rust中函数可以显式的return或者不显式直接会自动返回结果
  4. isize和usize和计算机系统有关一般不使用,默认整数类型是i32,浮点数优化后f64和f32计算速度近似,所以默认是f64
  5. Rust支持整数数列,支持开闭区间(1…5)=1,2,3,4;(1…=5)=1,2,3,4,5,结合for in可以实现类似于Python中 for in range的循环方式,.rev()方法可以直接反转数列
  6. Rust支持元组类型(),如果只有一个元素,需要在元素后跟随“,”来区分元组和括号表达式,同时元组支持嵌套和不同类型的数据存放在同一个元组中
  7. 数组类型支持省略初始化,类似于Python"*"符号的填充let arr=[1;5](let arr=[1,1,1,1,1])
  8. Vec数组类型是动态数组,可以增长和缩短容器,可以直接取值也可以使用get()方法来解决数组越界问题,内存是连续的存储块,只能存储相同类型的元素,所有的新元素会自动的添加在动态数组的尾部let mut v:Vec<i32>=Vec::new()或者可以创建指定长度的动态数组let mut v:Vec<i32>=Vec::with_capacity(10)也可使用宏来创建let mut v = vec![0;10],使用push()方法加入数据,pop()方法删除,remove可以删除指定索引,并将后方所有元素左移。
  9. VecDeque是一种双端队列,可以实现栈和队列功能(但是只能对两端元素进行操作,但是可以直接改变中间元素的值同时支持remove)push_front()/push_back(),pop_front()/pop_back()
  10. HashMap结构体要求键值对所有值都是同一类型,所有值也是同一类型,键不能重复。std::collections模块中,插入数据时使用entry和or_insert(检查是否有对应的值,没有对应的值就插入键值对),支持迭代器for in *。
  11. Rust中str是定长字符串,String是变长字符串本质是一个Vec<u8>类型的结构体(指向堆上字节序列指针as_ptr堆上字节长度len分配堆容量capacity),如果对两个String类型的字符串使用“+/+=”会返回新的字符串,而不是追加字符串(String+str)。
  12. format!宏可以格式化String和&str。
  13. 字符串的便利是通过UTF-8编码的字节序列进行访问,字符处理时按char进行返回
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/824061
推荐阅读
相关标签
  

闽ICP备14008679号