Rust修仙笔记下境界-筑基期

在上一节中我们了解了rust最基础的使用,如何使用宏打印,用了一个最简单的猜数游戏了解了rust中的基本用法,今天我们还是从rust中的基础知识中去学习rust

变量不可变性

当我用let声明一个name变量时,这个变量是不可变的

rust 复制代码
fn main() {
    let name = "Maic";
    println!("Hello, {}!", name);
}

当我们重新对name进行覆值时会报错

rust 复制代码
fn main() {
    let name = "Maic";
    name = "2";
    println!("Hello, {}!", name);
}

/**
2 |     let name = "Maic";
  |   ------ expected due to this value
3 |     name = '2';
  |            ^^^ expected `&str`, found `char`
**/

变量的可变性

如果我想让一个申明的变量可变,只需用mut修饰即可,注意我们右侧的变量用双引号,不能用单引号。

rust 复制代码
fn main() {
    let mut name = "Tom";
    println!("Hello, {}!", name);
    name = "Jake";
    // name = 'jake' error
    println!("Hello, {}!", name);
}
/*
  打印的结果是:
  Hello, Tom!
  Hello, Jake!
*/

常量

我是使用const申明变量,且变量名是大驼峰命名,且申明这个变量,我们使用u32类型

rust 复制代码
fn main() {
    const NAME_RESULT: u32 = 60 * 60;
    println!("Hello, {}!", NAME_RESULT);
}

遮蔽变量

我们使用let变量重复定义同一个变量名,这样会导致,第二个变量是前一个变量的引用

rust 复制代码
fn main(){
   // 1
   let x:i32 = 5;
   // 2
   let x:i32 = x + 1;
   {
     // 3
     let x:i32 = x + 3;
     println!("hello x1={}",x);
   }
   // 4
   println!("hello x2={}", x)
}

我们会发现我们重复申明了x3次,打印的结果是x1=9 x2=6。 在第2行申明的x,引用的就是1处申明的变量,在第3行使用的是第二2行申明的变量,{}可以申明成一个独立的块作用域,而4引用就是2处申明的变量。

从结果上来看,21遮蔽了,32遮蔽了,但是4引用的是2处的变量

遮蔽变量类型不可变

在以上我们重复用let定义了不可变量,我们发现遮蔽变量不可重新赋值且类型不可变

bash 复制代码
fn main() {
  let y:u32 = 5;
  y = 10; // cannot mutate immutable variable `y`
  println!("hello, {}", y)
}

要解决这个问题,我们只需把y变成mut即可,将该变量申明成一个可变量

bash 复制代码
fn main() {
  let mut y:u32 = 5;
  y = 10;
  println!("hello, {}", y)
}

那什么类型不可变,比如说:

bash 复制代码
fn main() {
    let str_name = "hello";
    str_name = str_name.len(); // error expected `&str`, found `usize`
    println!("hello, {}", str_name);    
}

我们用let申明了一个不可变变量,然后又重新赋值,并且获取了字符串的长度

此时打印str_name编辑就提示报错了 当我们使用不可变量想能重新赋值时,类型不可强制转换

rust 复制代码
// ok
fn main() {
   let str_name = "hello";
   let str_name = str_name.len();
   println!("hello length, {}", str_name); // 5
}

// error
fn main() {
    let mut str_name = "hello";
    str_name = str_name.len(); // 获取字符串的长度,
    println!("hello length, {}", str_name);
}

综上,我们会发现,在同一作用域内,当我们使用let申明同一个变量时,会存在变量遮蔽,不同作用域,会使用最近申明的遮蔽变量

注意在rust中我们声明的变量是小驼峰命名。当我们使用的一个mut申明的变量,再没有使用时候,会警告

rust 复制代码
fn main() {
    let mut y: u32 = 5;
    y = 10;
    println!("hello2, {}", y);
}

数据类型

rust中主要有以下两大类类型标量类型复合类型

其中标量类型主要有四种:整型浮点型布尔型字符

复合类型主要有元组类型数组类型

在以上我们使用let定义了一个不可变的变量,在rust中在编译期就知道其变量类型。

如果我想把字符串类型转换成数字类型,那如何做到呢?

rust 复制代码
fn main() {
    let guess_number = "12";
    let guess_number: u32 = guess_number.parse().expect("not a number");
    println!("guess number, {}", guess_number);
}

我们通过调用guess_number.parse()方法将字符串转换成了数字类型。

整型类型里主要有两大类,有符号(i)类型、无符号(u),在有符号(i)类型主要有i8(-128~127),i16,i32,i64,i128,在无符号(u)上类型主要有u8(0-255),u16(0-2^16-1),u32(2^32-1),u64,u128

  • 整型
rust 复制代码
// 有符号类型
let x:i8 = 10;
println!('{}',x);
// 无符号类型
let y:u8 = 20;
println!('{}',y);
  • 浮点型
rust 复制代码
let float_number:f32 = 2.5;
println!("float_number,{}", float_number);
  • 布尔类型
rust 复制代码
let is_true:bool = true;
println!('float_number,{}', is_true);
  • 字符串型
rust 复制代码
let a_num:&str = 'hello'

复合类型

rust中复合类型主要包含以下两种,一是元组(多种类型组合在一起形成一种复合类型,也就是元组),二是数组(同一种数据类型组合在一起,且有长度)

  • 元组类型

定义的类型一一对应,主要有(i32,f64,u8)三种类型

rust 复制代码
fn main() {
  let tuple_number: (i32,f64, u8) = (800,1.2,5);
  println!('tuple_number-0', tuple_number.0);
  println!('tuple_number-1', tuple_number.1);
  println!('tuple_number-2', tuple_number.2);
}

对元组进行解构

rust 复制代码
let (x,y,z) = tuple_number;
  • 数组 可以有以下几种方式
rust 复制代码
let name_array:[i32;5] = [1,2,3,4,5];

let name_array = ['a';5];
// 以上等价于
let name_array = ['a','a', 'a', 'a', 'a']

如何获取一个数组栈内存分配的大小

mem::size_of_val(&DATA_NUMBER)获取栈内存的大小

rust 复制代码
use std::mem;

fn main() {
    // 申明数组的长度
    const DATA_NUMBER: [i32; 5] = [1, 2, 3, 4, 5];
    println!("data is length {}", DATA_NUMBER.len());
    // data在内存中
    println!("data is {:?}", mem::size_of_val(&DATA_NUMBER));
}

自定义类型

rust中可以自定义类型,主要自定义类型方式有两种,一是结构体,二是枚举方式

#[derive(Debug)]

rust 复制代码
#[derive(Debug)]
struct Person {
    name: String,
    age: i8,
}
fn main() {
  let name = String::from("Maic");
  let age = 18;
  let user_info = Person {name, age};
  println!("user.name:{},user.age:{}", user_info.name, user_info.age);
  // 解构
  let Person{name, age} = user_info;
  println!("{},{}",name, age);
}
  • 解构元组
rust 复制代码
// 带有两个字段的解构体
struct Point {
   x:f32,
   y:f32
}

struct Pair(i32,f32);

fn main() {
  let x = 1.1;
  let y = 1.2;
  let point:Point = Point {x,y};
  println!("x={},y={}",point.x,point.y);
  let pair = Pair(1.1,3.4);
  let Pair(x,y) = pair;
  println!("x={},y={}", x,y);
}

枚举

我们使用enum关键词定义了WebEvent,在这个枚举中我们看到有 PageLoadPageUnloadKeyPress(char)Paste(String)Click {x: i64, y:i64}

rust 复制代码
// 主要用于隐藏对未使用代码的警告
#![allow(dead_code)]

enum WebEvent {
   PageLoad,
   PageUnload,
   KeyPress(char), // 元组结构体
   Paste(String),
   Click { x: i64, y: i64 },
}

// 将枚举WebEvent当成inspect的形参
fn inspect(event: WebEvent) {
    match event {
        WebEvent::PageLoad => println!("page loaded"),
        WebEvent::PageUnload => println!("page unload"),
        WebEvent::KeyPress(c) => println!("keypress:{}", c),
        WebEvent::Paste(s) => println!("Paste,{}", s),
        WebEvent::Click { x, y } => {
            println!("x={},y={}", x, y)
        }
    }
}
fn main() {
    let pressed = WebEvent::KeyPress('x');
    let pasted = WebEvent::Paste("my name".to_owned());
    let click = WebEvent::Click { x: 20, y: 80 };
    let load = WebEvent::PageLoad;
    let unload = WebEvent::PageUnload;
    let x = OtherVeryVerBoseEnum::Add;
    inspect(pressed);
    inspect(pasted);
    inspect(click);
    inspect(load);
    inspect(unload);
    println!("Hello, world!");
}

use

当我们使用enum申明了一个枚举时,在main方法中可以使用use关键词引入Work

rust 复制代码
#![allow(dead_code)]

enum Work {
  Civilian,
  Soldier
}

fn main () {
   use Work::*;
   // 与下面等价
   /*
     use Work::{Civilian, Soldier}
   */
   let work_civilian = Civilian;
   match work_civilian {
     Civilian => println!("the civilian"),
     Soldier => println!("soldiers fight")
   }
}

if

if条件语句,当我们使用if条件时,可以将判断后的语句进行赋值操作

js 复制代码
fn main() {
    let number = 10;
    // 注意if后面并没有括号
    let new_number = if number < 0 {
        println!("to small");
        -10 // 注意这里没有分号,会赋值给表达式new_number
    } else {
        println!("to big");
        100 // 这里也会赋值表达式new_number
    };
    println!("{}", new_number);
}

for循环

循环一个范围数据,比如[a,b]之间

rust 复制代码
fn main() {
    // for循环a..=b 表示[a,b]范围
    for item in 1..=10 {
        println!("item1: {}", item);
    }
    // a..b 表示[a,b)范围
    for item in (1..11).rev() {
        println!("item,{}", item);
    }
    // vec!申明一个可迭代器的变量
    let names = vec!["a", "b", "c"];
    for item in names.iter() {
        match *item {
            "a" => println!("There is a rustacean among us!"),
            _ => println!("Hello {}", item),
        }
    }
}

可以修改循环中的数组,使用names3.iter_mut()

rust 复制代码
 let mut names3 = vec!["Bob", "Frank", "Ferris"];
    for name in names3.iter_mut() {
        *name = match name {
            &mut "Ferris" => "hello",
            _ => "a",
        }
    }
    println!("names3:{:?}", names3);
    // names3:["a", "a", "hello"]

match

匹配对应条件,并返回,当我们使用match时,如果条件不满足会默认走_ => println!("other case!"),如果满足其中任意条件,则会走其中任意一分支,如果match返回一个值,则会走match匹配的分支

rust 复制代码
fn main() {
    let number = 2;
    println!("number is {}", number);
    match number {
        1 => println!("first one"),
        2 | 3 => println!("{}", number),
        5..=6 => println!("good luck"),
        _ => println!("other case!"),
    };

    let boolean = false;
    let binary = match boolean {
        false => "false",
        true => "true",
    };
    println!("{} -> {}", boolean, binary);
}

enum

rust 复制代码
// 消除警告,使用枚举类型取值
#[allow(dead_code)]
// 加了这个不会报错,第15【Color::Red => println!("color is red,{:?}", color)】行不会报错
#[derive(Debug)]
enum Color {
    Red,
    Blue,
}

fn main() {
    // &表示取引用
    let reference = &4;
    let color = Color::Red;
    match color {
        Color::Red => println!("color is red,{:?}", color),
        Color::Blue => println!("color is blue"),
    }
    match reference {
        // &val指向的是reference
        &val => println!("value is {}", val),
    }
    // 等价于上面,使用*引用,这样val不用加&
    match *reference {
        val => println!("value2 is {}", val),
    }
    // 没有引用
    let no_reference = 3;
    match no_reference {
        val => println!("value3 is {}", val),
    }
    match no_reference {
        ref val => println!("value4 is {}", val),
    }
    let mut value = 10;

    match value {
        ref mut val => {
            // 先用*解引用,然后+10
            *val += 10;
            println!("value5 is {}", val);
        }
    }
}

总结

  • 我们学习到了rust中的可变变量与不可变量,通常来讲使用let申明的变量是不可变的,而且在rust中可以重复定义同一变量名,但此时会发生遮蔽变量。

  • 我们学习了rust中最基本的数据类型,主要分两大类,标量类型复合类型,其中标量类型主要包含,整型浮点型布尔型字符串型,复合类型主要包括,元组类型数组类型

  • 了解到use,if,match,forenum的使用

  • 本文示例代码code example

相关推荐
老猿讲编程2 小时前
用示例来看C2Rust工具的使用和功能介绍
rust
金庆2 小时前
How to set_default() using config-rs crate
rust·config·set_default·valuekind
许野平4 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
‍。。。15 小时前
使用Rust实现http/https正向代理
http·https·rust
Source.Liu15 小时前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng15 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马15 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng15 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
hikktn1 天前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
睡觉谁叫~~~1 天前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust