• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Rust 笔记

武飞扬头像
Little_Fall
帮助1

https://rustwiki.org/zh-CN/rust-by-example/custom_types/constants.html

1 print!

  • fmt::Debug:使用 {:?} 标记。格式化文本以供调试使用。需要 #[derive(Debug)]
    可以使用 {:#?} 来获得更规范的数据结构的打印
  • fmt::Display:使用 {} 标记。以更优雅和友好的风格来格式化文本
println!("Pi is roughly {:.3}", pi);
#[derive(Debug)]
struct Complex {
    real: f64,
    imag: f64,
}

impl fmt::Display for Complex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}   {}i", self.real, self.imag)
    }
}

    
    println!("Display: {}", complex);
    println!("Debug: {:?}", complex)

impl Display for Color {
    // RGB (0, 3, 254) 0x0003FE
    // TODO: use for loop to print three properties
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "RGB ({}, {}, {}) 0x{:02X}{:02X}{:02X}", 
            self.red, self.green, self.blue, self.red, self.green, self.blue)
    }
}

2 变量

实在无法推断类型时,按 i32/f64 使用

use std::fmt;
use std::fmt::Formatter;

// 元组可以充当函数的参数和返回值
fn reverse(pair: (i32, bool)) -> (bool, i32) {
    // 可以使用 `let` 把一个元组的成员绑定到一些变量
    let (integer, boolean) = pair;

    (boolean, integer)
}

// 在 “动手试一试” 的练习中要用到下面这个结构体。
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);

impl fmt::Display for Matrix {
    // ( 1.1 1.2 )
    // ( 2.1 2.2 )
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "( {} {} )\n", self.0, self.1)?;
        write!(f, "( {} {} )", self.2, self.3)
    }
}

fn transpose(old: Matrix) -> Matrix {
    Matrix(old.0, old.2, old.1, old.3)
}

fn main() {
    // 包含各种不同类型的元组
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // 通过元组的下标来访问具体的值
    println!("long tuple first value: {}", long_tuple.0);
    println!("long tuple second value: {}", long_tuple.1);

    // 元组也可以充当元组的元素
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

    // 元组可以打印
    println!("tuple of tuples: {:?}", tuple_of_tuples);

    // 但很长的元组无法打印
    // let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
    // println!("too long tuple: {:?}", too_long_tuple);
    // 试一试 ^ 取消上面两行的注释,阅读编译器给出的错误信息。

    let pair = (1, true);
    println!("pair is {:?}", pair);

    println!("the reversed pair is {:?}", reverse(pair));

    // 创建单元素元组需要一个额外的逗号,这是为了和被括号包含的字面量作区分。
    println!("one element tuple: {:?}", (5u32,));
    println!("just an integer: {:?}", (5u32));

    // 元组可以被解构(deconstruct),从而将值绑定给变量
    let tuple = (1, "hello", 4.5, true);

    let (a, b, c, d) = tuple;
    println!("{:?}, {:?}, {:?}, {:?}", a, b, c, d);

    let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
    println!("debug: {:?}", matrix);
    println!("display: \n{}", matrix);

    println!("Matrix:\n{}", matrix);
    println!("Transpose:\n{}", transpose(matrix));
}

学新通

元组 (, , )

数组的类型标记为 [T; size]

切片是一个双字 对象(two-word object),第一个字是一个指向数据的指针,第二个字是切片的长度。

Rust 自定义数据类型主要是通过下面这两个关键字来创建:

struct: 定义一个结构体(structure)
enum: 定义一个枚举类型(enumeration)
而常量(constant)可以通过 const 和 static 关键字来创建。

#[derive(Debug)]
struct Person<'a> {
    name: &'a str,
    age: u8,
}

// 单元结构体
struct Nil;

// 元组结构体
struct Pair(i32, f32);

#[derive(Debug)]
// 带有两个字段(field)的结构体
struct Point {
    x: f32,
    y: f32,
}

// 结构体可以作为另一个结构体的字段
#[allow(dead_code)]
#[derive(Debug)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn rect_area(rec: &Rectangle) -> f32 {
    let Rectangle {
        p1: Point { x: x1, y: y1},
        p2: Point { x: x2, y: y2},
    } = rec;
    ((x1-x2) * (y1-y2)).abs()
    //((rec.p1.x-rec.p2.x) * (rec.p1.y-rec.p2.y)).abs
}

fn square(p: Point, len: f32) -> Rectangle {
    Rectangle {
        p1: Point { x: p.x, y: p.y len },
        p2: Point { x: p.x len, y: p.y },
    }
}

fn main() {
    // 使用简单的写法初始化字段,并创建结构体
    let name = "Peter";
    let age = 27;
    let peter = Person { name, age };

    // 以 Debug 方式打印结构体
    println!("{:?}", peter);

    // 实例化结构体 `Point`
    let point: Point = Point { x: 0.3, y: 0.4 };

    // 访问 point 的字段
    println!("point coordinates: ({}, {})", point.x, point.y);

    // 使用结构体更新语法创建新的 point,这样可以用到之前的 point 的字段
    let new_point = Point { x: 0.1, ..point };

    // `new_point.y` 与 `point.y` 一样,因为这个字段就是从 `point` 中来的
    println!("second point: ({}, {})", new_point.x, new_point.y);

    // 使用 `let` 绑定来解构 point
    let Point { x: my_x, y: my_y } = point;

    let _rectangle = Rectangle {
        // 结构体的实例化也是一个表达式
        p1: Point { x: my_y, y: my_x },
        p2: point,
    };

    // 实例化一个单元结构体
    let _nil = Nil;

    // 实例化一个元组结构体
    let pair = Pair(1, 0.1);

    // 访问元组结构体的字段
    println!("pair contains {:?} and {:?}", pair.0, pair.1);

    // 解构一个元组结构体
    let Pair(integer, decimal) = pair;

    println!("pair contains {:?} and {:?}", integer, decimal);

    let r1 = Rectangle { p1: Point{x:1.0, y:2.0}, p2: Point{x:3.0, y:4.0} };
    let r2 = Rectangle { p1: Point{x:3.0, y:2.0}, p2: Point{x:3.0, y:4.0} };
    println!("the area of rectangle {:?} is {}", r1, rect_area(&r1));
    println!("the area of rectangle {:?} is {}", r2, rect_area(&r2));

    let p1 = Point{x:1.0, y:2.0};
    let len = 3.3;
    let s1 = square(p1, len);
    println!("the area of rectangle {:?} is {}", s1, rect_area(&s1))
}

学新通

enum,match

类型别名 type Operations = VeryVerboseEnumOfThingsToDoWithNumbers,最常见的情况就是在 impl 块中使用 Self 别名。

Rust 有两种常量,可以在任意作用域声明,包括全局作用域。它们都需要显式的类型声明:

const:不可改变的值(通常使用这种)。
static:具有 'static 生命周期的,可以是可变的变量(译注:须使用 static mut 关键字)。

const 和 let 的区别:const 一定会被编译期计算,let 只会检查生命周期。

变量绑定:

  1. 变量名前面加下划线可以忽视未使用的警告
  2. 可以先声明再初始化,编译器会检查

类型系统:

  1. 基本类型不能隐式转换,可以使用 xxx as u8 进行显式转换。
  2. 整数间转换是直接切位
  3. 数值字面量可以直接把类型写在后面,没写就是 i32, f64;std::mem::size_of_val(&x) 类似于 sizeof
  4. 类型推导比较聪明,可以从后文推导
  5. 别名,type a = b.

类型转换

  1. From 和 Into,实现了 from 也就可以用 into
use std::convert::From;

#[derive(Debug)]
struct Number {
    value: i32,
}

impl From<i32> for Number {
    fn from(item: i32) -> Self {
        Number { value: item }
    }
}

fn main() {
    let num = Number::from(30);
    println!("My number is {:?}", num);
}

fn main() {
    let int = 5;
    // 试试删除类型说明
    let num: Number = int.into();
    println!("My number is {:?}", num);
}
学新通
  1. tryFrom 和 tryInto,结果返回 result
  2. 没必要实现 ToString,可以直接实现 fmt::Display;
  3. 如果想调用 parse,可以实现 FromString

表达式

  1. rust 中最常用的语句有两种:1. 变量绑定(一定需要分号) 2. 表达式(可能跟着分号)
  2. 代码块也是表达式,值 = 最后执行的语句的值(如果最后执行的语句有分号,那么值是()

流程

  1. if-else 语句也是表达式,条件不用小括号,代码块必须要大括号,所有分支返回类型必须相同
  2. 无限循环:loop {}
  3. 循环标签:
#![allow(unreachable_code)]

fn main() {
    'outer: loop {
        println!("Entered the outer loop");

        'inner: loop {
            println!("Entered the inner loop");

            // 这只是中断内部的循环
            //break;

            // 这会中断外层循环
            break 'outer;
        }

        println!("This point will never be reached");
    }

    println!("Exited the outer loop");
}
学新通
  1. break 后面可以跟着返回值
  2. while 循环
  3. for in <iterator>,比如 for in 1..101
    迭代器生成方式:
    • 1…101 左闭右开
    • 1…=100 闭区间
    • vec.into_iter() 默认方式,转变成 iter 并消耗
    • vec.iter() 依次借用集合中的元素
    • vec.mut_iter() 可变地借用集合中的元素

match

  1. match 匹配:解构,分支可以是 1|3|4,也可以是 3..20
  2. & 取引用,* 解引用,let ref 获得引用
  3. match 中,&val 会匹配一个引用并解开,val 是一个值类型。而 ref r 会匹配一个引用但不解开,r 是一个引用类型。
fn main() {
    // 获得一个 `i32` 类型的引用。`&` 表示取引用。
    let reference = &4;

    match reference {
        // 如果用 `&val` 这个模式去匹配 `reference`,就相当于做这样的比较:
        // `&i32`(译注:即 `reference` 的类型)
        // `&val`(译注:即用于匹配的模式)
        // ^ 我们看到,如果去掉匹配的 `&`,`i32` 应当赋给 `val`。
        // 译注:因此可用 `val` 表示被 `reference` 引用的值 4。
        &val => println!("Got a value via destructuring: {:?}", val),
    }

    // 如果不想用 `&`,需要在匹配前解引用。
    match *reference {
        val => println!("Got a value via dereferencing: {:?}", val),
    }

    // 如果一开始就不用引用,会怎样? `reference` 是一个 `&` 类型,因为赋值语句
    // 的右边已经是一个引用。但下面这个不是引用,因为右边不是。
    let _not_a_reference = 3;

    // Rust 对这种情况提供了 `ref`。它更改了赋值行为,从而可以对具体值创建引用。
    // 下面这行将得到一个引用。
    let ref _is_a_reference = 3;

    // 相应地,定义两个非引用的变量,通过 `ref` 和 `ref mut` 仍可取得其引用。
    let value = 5;
    let mut mut_value = 6;

    // 使用 `ref` 关键字来创建引用。
    // 译注:下面的 r 是 `&i32` 类型,它像 `i32` 一样可以直接打印,因此用法上
    // 似乎看不出什么区别。但读者可以把 `println!` 中的 `r` 改成 `*r`,仍然能
    // 正常运行。前面例子中的 `println!` 里就不能是 `*val`,因为不能对整数解
    // 引用。
    match value {
        ref r => println!("Got a reference to a value: {:?}", r),
    }

    // 类似地使用 `ref mut`。
    match mut_value {
        ref mut m => {
            // 已经获得了 `mut_value` 的引用,先要解引用,才能改变它的值。
            *m  = 10;
            println!("We added 10. `mut_value`: {:?}", m);
        },
    }
}
学新通
  1. match 可以加 if,这叫做 guard
    match pair {
        (x, y) if x == y => println!("These are twins"),
        // ^ `if` 条件部分是一个卫语句
        (x, y) if x   y == 0 => println!("Antimatter, kaboom!"),
        (x, _) if x % 2 == 1 => println!("The first one is odd"),
        _ => println!("No correlation..."),
    }
  1. 可以使用 @ 边匹配边绑定
    match age() {
        0             => println!("I haven't celebrated my first birthday yet"),
        // 可以直接匹配(`match`) 1 ..= 12,但那样的话孩子会是几岁?
        // 相反,在 1 ..= 12 分支中绑定匹配值到 `n` 。现在年龄就可以读取了。
        n @ 1  ..= 12 => println!("I'm a child of age {:?}", n),
        n @ 13 ..= 19 => println!("I'm a teen of age {:?}", n),
        // 不符合上面的范围。返回结果。
        n             => println!("I'm an old person of age {:?}", n),
    }
  1. match 需要覆盖全部情况,如果不想用 _,可以使用 if let 尝试解构
// 该枚举故意未注明 `#[derive(PartialEq)]`,
// 并且也没为其实现 `PartialEq`。这就是为什么下面比较 `Foo::Bar==a` 会失败的原因。
enum Foo {Bar}

fn main() {
    let a = Foo::Bar;

    // 变量匹配 Foo::Bar
    // if Foo::Bar == a { // 编译错误,因为不能比较
    if let Foo::Bar = a { //编译成功
        println!("a is foobar");
    }
}
  1. while let
fn main() {
    // 将 `optional` 设为 `Option<i32>` 类型
    let mut optional = Some(0);

    // 这读作:当 `let` 将 `optional` 解构成 `Some(i)` 时,就
    // 执行语句块(`{}`)。否则就 `break`。
    while let Some(i) = optional {
        if i > 9 {
            println!("Greater than 9, quit!");
            optional = None;
        } else {
            println!("`i` is `{:?}`. Try again.", i);
            optional = Some(i   1);
        }
        // ^ 使用的缩进更少,并且不用显式地处理失败情况。
    }
    // ^ `if let` 有可选的 `else`/`else if` 分句,
    // 而 `while let` 没有。
}
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhhiggbh
系列文章
更多 icon
同类精品
更多 icon
继续加载