Rust Tips #1 ~#20

569次阅读  |  发布于3月以前

Tip #001


Rust 不支持静态 vec(static vec),但是最接近的是静态数组。例如,如果你想存储三个字符串的数组,可以尝试这样: static STRINGS : [&str;3] = ["a", "b", "c"]

Tip #002

什么是可选值(optional)和 unwrap()? 可以将可选值想象成一个信封,它可以包含一个值(Some(item))或者什么都没有(None)。对可选值调用 unwrap() 要么返回包含的值,要么如果可选值是 None 的话就会使程序 panic。

Tip #003

关于可选值( optional)的安全解包方式:

Tip #004

如果你没有时间完成特定的一段代码,但仍然希望程序可以编译,可以考虑使用 todo!()unimplemented!() 宏。你的代码会继续编译通过,但如果程序运行到包含这些宏的代码块中,它将会 panic。

todo! 更适合临时标记,而 unimplemented! 则更适合长期未实现的情况。

Tip #005

如果你想测试一个枚举类型的实例是否符合枚举的特定变体,你可以使用 matches! 宏,例如:let match_res = matches!(my_variable, enum_type);

你也可以匹配其他模式,如范围,例如: matches!(foo, 'A'..='Z')

Tip #006

你知道吗, {} 块可以像函数一样返回结果?这使得基于条件的赋值变得非常容易。例如:

let car_ready = {
      start_engine();
      match engine_state {
       Engine::running => true,
       Engine::error => false
   }
}

Tip #007

const 和 static 之间有什么区别?

Tip #008

如果你想将几个相同或不同类型的值一起存储,元组类型就很有用。下面是一个将元组类型声明为结构体元组的示例,访问元组类型字段,以及从函数返回"匿名"元组类型:

struct MyTuple(String, i32);

fn flip(a: (i32, String)) -> MyTuple {
    let my_tuple = MyTuple(String::from("the answer"), 42);
    (a.1, a.0)
}

Tip #009

让我们来谈谈 string

在 Rust 中有两种基本的字符串类型: Stringstr

String: (也称为 Owned String),在堆上分配内存并且可变。String 在运行时使用,当你想要创建和修改字符串时。你可以将 String 作为 &str 引用传递给只读函数。

str: (也称为 String Slice) 是对一序列 UTF8 数据的引用。你可以在编译时以常量、静态字面量的形式创建 str,或者在运行时从 String 对象获取它们。str 总是不可变的。

Tip #010

拼接 string 有两种方式可以将两个字符串连接,分别使用:

// 使用 push_str
let mut first = String::from("Hello, ");
first.push_str("world!");
assert_eq!(first, "Hello, world!");

// 使用 format! 宏
let second = String::from("Hello, ");
let combined = format!("{}{}", second, "world!");
assert_eq!(combined, "Hello, world!");

Tip #011

格式化打印宏

Tip #012

可选值解包使用 if let() 类似于 Swift , Rust 允许我们使用 if let 来测试一个可选值是否有值,这种方式便于保持程序流程的简洁:

fn main() {
    let optional_value: Option<i32> = Some(9);

    // 传统方式
    match optional_value {
        Some(value) => println!("The value is: {}", value),
        None => println!("There is no value"),
    }

    // 使用 if let
    if let Some(value) = optional_value {
        println!("The value is: {}", value);
    } else {
        println!("There is no value");
    }
}

Tip #013

使用 if let 解包多个可选值。继上一条 tip,如果你需要同时检查多个可选值是否都有值,你可以使用 if let 来测试和解包可选值的元组:

fn main() {
    let optional_tuple: (Option<i32>, Option<bool>) = (Some(5), Some(true));

    // 传统方式
    match optional_tuple {
        (Some(int_value), Some(bool_value)) => {
            println!("Received int: {} and bool: {}", int_value, bool_value);
        }
        _ => println!("One or more options were None"),
    }

    // 使用 if let
    if let (Some(int_value), Some(bool_value)) = optional_tuple {
        println!("Received int: {} and bool: {}", int_value, bool_value);
    } else {
        println!("One or more options were None");
    }
}

Tip #014

实例化 vector。Vec 是一种动态数组类型,非常适合存储相同数据类型的序列。下面是一些使用标准库调用和 vec!宏实例化 Vec 的方式。注意类型是如何处理的:

// Type automatically inferred by the next push.
let mut a: Vec<i64> = Vec::new();
a.push(1_i64);

// Type set during instantiation.
let mut b: Vec<i64> = Vec::<i64>::new();

// Type defined explicitly, initialized using vec!
let mut c: Vec<i64> = vec![];

// Type automatically inferred, prefilled with vec!
let mut d: Vec<i64> = vec![1_i64, 2_i64, 3_i64];
// 空Vec
let mut vec1: Vec<i32> = Vec::new();

// 用值初始化
let mut vec2 = vec![1, 2, 3];

// 用指定数量的元素和默认值初始化
let mut vec3 = vec![0; 5]; // vec3 = [0, 0, 0, 0, 0]

// 从迭代器获取元素
let vec4 = (0..5).collect();
let vec5: Vec<_> = ["foo", "bar"].into_iter().collect();

// 用给定的初始容量初始化
let mut vec6 = Vec::with_capacity(10);

Tip #015

Vector 迭代。

你可以使用 vec.iter() 来对 Vector 进行迭代,使用 map()for_each() 函数,这与例如 JavaScript 中的方式类似。

let numbers: Vec<i32> = vec![1, 2, 3, 4, 5];

// Using for_each to print each element
numbers.iter().for_each(|&x: i32| {
    println!("{}", x);
});

// Use map to transform a vector.
let squared: Vec<i32> = numbers.iter().map(|&x: i32| x * x).collect();

println!("{:?}", squared);

Tip #016

嘿,你有一些不错的HashMap,怎么初始化它们?除了创建一个新的HashMap并插入键值对之外,一种值得注意的方式是使用一个元组数组和一个#迭代器:

use std::collections::HashMap;

fn main() {
    // 从一个元组数组创建HashMap
    let codes: HashMap<_, _> = [
        (101, "abc"),
        (102, "def"),
        (103, "ghi"),
    ].iter().cloned().collect();

    println!("codes = {:?}", codes);
}

Tip #017

更好的方式来unwrap()如果内容是None的话,unwrap()一个可选值会导致 panic。以下是在unwrap时处理 None 的一些方法:

fn main() {
    let x: Option<i32> = None;

    // 返回默认值0
    println!("{}", x.unwrap_or_default());

    // 返回提供的替代值99
    println!("{}", x.unwrap_or(99));

    // 返回函数提供的值
    println!("{}", x.unwrap_or_else(|| "No value".to_string()));
}

Tip #018

Rust 允许我们轻松定义匿名函数(也称为lambdaclosure 或闭包)。闭包通常与 iterator 一起使用,或者用于定义回调函数。以下是语法示例:

fn main() {
    let multiply = |a, b| a * b;
    let product = multiply(3, 4);
    println!("Product: {}", product); // 输出: Product: 12

    let add_two = |x| x + 2;
    let values = vec![1, 2, 3, 4, 5];
    let new_values: Vec<_> = values.iter().map(add_two).collect();
    println!("New values: {:?}", new_values); // 输出: New values: [3, 4, 5, 6, 7]
}

Tip #019

闭包中使用 move 可以从周围作用域捕获变量。这意味着闭包将获取这些变量的所有权,而无需传递任何参数:

fn main() {
    let num = 5;

    let closure = || {
        println!("Num: {}", num); // 错误: `num` 不可借用
    };

    let closure_move = move || {
        println!("Num: {}", num); // 正确: `num` 被移动到闭包中
    };

    closure(); // 调用没有捕获变量的闭包
    closure_move(); // 调用捕获了 `num` 的闭包
}

Tip #020

实现 From() trait 提供了一种在复杂类型之间进行转换的机制。Rust 还会自动为对应的类型提供一个 Into() 实现。在下面的示例中,我们为 ColorFloat 实现了 From,但是可以使用 Color8BitInto():

struct Color8Bit {
    r: u8,
    g: u8,
    b: u8,
}

struct ColorFloat {
    r: f32,
    g: f32,
    b: f32,
}

impl From<Color8Bit> for ColorFloat {
    fn from(color: Color8Bit) -> Self {
        ColorFloat {
            r: (color.r as f32) / 255.0,
            g: (color.g as f32) / 255.0,
            b: (color.b as f32) / 255.0,
        }
    }
}

fn main() {
    let color8 = Color8Bit { r: 230, g: 100, b: 50 };

    // 使用 Into 特性将 Color8Bit 转换为 ColorFloat
    let color_float: ColorFloat = color8.into();

    println!("Color Float: {}, {}, {}", color_float.r, color_float.g, color_float.b);
}

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8