0%

零散的语法

Rust By Practice 中get的琐碎知识

  • 忽略对未使用变量的警告
    1
    2
    3
    4
    // method 1
    #[allow(unused_variables)]
    // method 2
    let _varname = 1 ;
  • 解构式赋值
    1
    2
    3
    4
    5
    6
    7
    8
    fn main() {
    let (x, y);
    (x, ..) = (3, 4);
    (.., y) = (3, 4);
    assert_eq!([x, y], [3, 2]);
    println!("{} {}", x, y)
    }

  • std::fmt

https://doc.rust-lang.org/stable/alloc/std/fmt/index.html

数字


  • i8 u8 … ::MAX

    1
    2
    assert_eq!(i8::MAX, 127);
    assert_eq!(u8::MAX, 255);

    取模的快速思考可以用移位思考

  • 进制与数字类型显式声明 ; i32 , f64 , _ 可省略

    1
    2
    3
    4
    5
    let x = 1_024 + 0b1111_0010 + 0o1723 + 0xffffff;
    // 10 2 8 16
    let x = 1_024_i32 ;
    let x = 0b1111_0010_u32 ;

  • 浮点数精度

    1
    2
    assert!(0.1_f32 + 0.2_f32 == 0.3_f32);
    assert!((0.1_f64 + 0.2 - 0.3).abs() < f64::EPSILON);
  • 像C系一样的溢出自动取模

    1
    2
    use std::num::Wrapping;
    let v1 = (Wrapping(251_u8) + Wrapping(8)).0;
  • GetTypeName

    1
    2
    3
    4
    fn type_of<T>(_: &T) -> String {
    format!("{}", std::any::type_name::<T>())
    }

  • for循环 [)

    1
    2
    3
    4
    for i in -3..2 {
    println!("{}", i);
    }
    // -3 -2 -1 0 1
  • Range 与 RangeInclusive

    1
    2
    3
    4
    5
    use std::ops::{Range, RangeInclusive};
    fn main() {
    assert_eq!((1..5), Range { start: 1, end: 5 }); // 不包含5
    assert_eq!((1..=5), RangeInclusive::new(1, 5)); // 包含5
    }
  • println 打印数字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
        let x = 5;
    println!("{}", x);
    println!("{:5}", x);
    println!("{:.5}", x);
    println!("{:5.5}", x);
    println!("{:05.5}", x);
    let x = 5.9;
    println!("{}", x);
    println!("{:5}", x);
    println!("{:.5}", x);
    println!("{:5.5}", x);
    println!("{:05.5}", x);
    let x = 15;
    println!("{:b}", x);
    println!("{:o}", x);
    println!("{:x}", x);
    /*
    5
    5
    5
    5
    00005
    5.9
    5.9
    5.90000
    5.90000
    5.90000
    5.90000
    1111
    17
    f
    */

字符,布尔,单元


  • char - utf8 - size=4
  • fn()默认返回()
  • ()类型 size=0
1
2
3
4
5
use std::mem::size_of_val;
fn main() {
let unit: () = ();
println!("size of `()` in bytes: {}", size_of_val(&unit));
}
  • 运算符表达式的返回值
  1. 赋值运算符: 返回空元组()
  2. 其他运算符: 返回运算结果

函数


  • 每个参数都要指定类型
  • 可以用!表示永不返回,常用于无限循环/panic!/unimplemented!()/todo!() , 这样的函数叫发散函数(Diverging function)
    1
    2
    3
    4
    5
    6
    fn never_return() -> ! {
    loop{};
    unimplemented!();
    todo!();
    panic!();
    }

String


String::from() 栈(ptr,cap,len)->堆 ; &str 栈(ptr,len) -> ReadOnly

1
2
3
let s1 = String::from("hello,");
let s2 = String::from("world!");
let s3 = s2 + &s1; // String,&str,s2所有权move to s3
  • 字符串转义
    1
    2
    3
    4
    5
    "\x73"
    "\u{211D}"
    r"disable \(Escape)"
    r#"allow " "# // 亦用于多行字符串
    r###"allow " and # "###
  • 字节字符串
    1
    2
    3
    let bytestring: &[u8; 21] = b"this is a byte string";
    //字节数组可以不是 UTF-8 格式
    let shift_jis = b"\x82\xe6\x82\xa8\x82\xb1\x82\xbb";
    • to str may be failed
      1
      2
      3
      if let Ok(my_str) = str::from_utf8(raw_bytestring) {
      println!("And the same as text: '{}'", my_str);
      }
  • 切片必须在边界:按char(8byte)索引
    1
    2
    let s1 = String::from("hi,中国");
    assert_eq!(h1, "中");
  • 按UTF-8字打印
    1
    2
    3
    for c in "你好,世界".chars() {
    println!("{}", c)
    }
  • 好用的utf8_slice: 按字索引
    1
    2
    3
    4
    5
    6
    7
    use utf8_slice;
    fn main() {
    let s = "The 🚀 goes to the 🌑!";

    let rocket = utf8_slice::slice(s, 4, 5);
    // 结果是 "🚀"
    }

array


  • 声明,必须固定大小
  • get方法返回Option<T>,非常安全,但直接使用下标不安全(越界时对于array直接通不过编译)
1
2
3
let arr: [i32;5] = [1, 2, 3, 4, 5];
let arr: [_; 3] = ['a', 'b', 'c'];
let arr = ['a', 'b', 'c'];

slice


占用空间: 3字(64位:16byte) [胖指针]

tuple


struct


Struct Data => 无 ;

  • Debug
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    fn main() {
    let scale = 2;
    let rect1 = Rectangle {
    width: dbg!(30 * scale), // print debug info to stderr and assign the value of `30 * scale` to `width`
    height: 50,
    };

    dbg!(&rect1); // print debug info to stderr

    println!("{:?}", rect1); // print debug info to stdout
    }

enum TODO


common: tag*n [i8/i32…]
fn,struct…: tag,fn…
Option<T> : T can be 0 => 同上 ; T cannot be 0 => no tag

  • 显式指定值
  • 枚举可以持有各种值
  • 模式匹配get值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
    }

    fn main() {
    let msg = Message::Move { x: 1, y: 2 };

    if let Message::Move { x: a, y: b } = msg {
    assert_eq!(a, b - 1);
    } else {
    panic!("不要让这行代码运行!");
    }
    }

Box


ptr->[Heap]

流程控制


1
2
3
4
5
6
7
8
fn main() {
let a = [4, 3, 2, 1];

// 通过索引和值的方式迭代数组 `a`
for (i, v) in a.iter().enumerate() {
println!("第{}个元素是{}", i + 1, v);
}
}
  • break后可以加值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    fn main() {
    let mut counter = 0;
    let result = loop {
    counter += 1;
    if counter == 10 {
    break counter * 2;
    }
    };

    assert_eq!(result, 20);
    }

模式匹配


  • if let 左 Pattern 右 值
  • struct模式匹配-部分匹配并赋值给变量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    match p {
    Point { x, y: 0 } => println!("On the x axis at {}", x),
    Point {
    x: 0..=5,
    y: y @ (10 | 20 | 30),
    } => println!("TWO::: On the y axis at {}", y),
    Point { x, y } => println!("On neither axis: ({}, {})", x, y),
    }

    new_var @ ( pattern)
  • 分支后可以if
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    fn main() {
    let num = Some(4);
    let split = 5;
    match num {
    Some(x) if split > x => assert!(x < split),
    Some(x) if split <= x => assert!(x >= split),
    None => (),
    Some(_) => unreachable!(),
    }
    }
  • 分支部分赋值
    1
    2
    3
    (first, .., last) =>{

    }
  • match修改ref或值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    fn main() {
    let mut v = String::from("hello,");
    let r = &mut v;

    match r {
    value => value.push_str(" world!"),
    }

    match v {
    ref mut value => value.push_str("!!!!"),
    }
    println!("{}", v);
    }

impl

  • self 是self:&Self的语法糖
  • 方法是实例的方法,关联函数是类型的关联函数

泛型

1
2
3
4
5
struct A;
struct B(A);
struct C<T>(T);
fn sum<T>(a:T,b:T){}
fn sum<T:std::ops::Add(Option=T)>(a:T,b:T){a+b}
  • impl块中函数有不同于impl对应struct/enum的type
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    impl<T, U> Point<T, U> {
    fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
    Point {
    x: self.x,
    y: other.y,
    }
    }
    }```
    - 这两个等价
    ```rust
    fn summary<T: Summary>(s: &T) -> String {
    s.summarize()
    }
    fn summary(t: &impl Summary) -> String {
    t.summarize()
    }
  • 离谱的const泛型

目前,const 泛型参数只能使用以下形式的实参:
一个单独的 const 泛型参数
一个字面量 (i.e. 整数, 布尔值或字符).
一个具体的 const 表达式( 表达式中不能包含任何 泛型参数)
简言之就是为了保证const无论怎么传递都是一个const(T很奇怪,为什么不能生成好几个参数,那(std::mem::size_of::<T>())不就也是const了吗)
通过将&str包裹成以const size为长度的arr struct 让编译器在编译时就知道&str长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
pub struct MinSlice<T, const N: usize> {
pub head: [T; N],
pub tail: [T],
}

fn main() {
let slice: &[u8] = b"Hello, world";
let reference: Option<&u8> = slice.get(6);
// 我们知道 `.get` 返回的是 `Some(b' ')`
// 但编译器不知道
assert!(reference.is_some());

let slice: &[u8] = b"Hello, world";

// 当编译构建 MinSlice 时会进行长度检查,也就是在编译期我们就知道它的长度是 12
// 在运行期,一旦 `unwrap` 成功,在 `MinSlice` 的作用域内,就再无需任何检查
let minslice = MinSlice::<u8, 12>::from_slice(slice).unwrap();
let value: u8 = minslice.head[6];
assert_eq!(value, b' ')
}
  • 注意一个泛型struct不是一个struct

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    struct Array<T, const N: usize> {
    data: [T; N],
    }

    fn main() {
    let arrays = [ // Error
    Array { data: [1, 2, 3] },// Array<i32,3>
    Array { data: [1.0, 2.0, 3.0] }, // Array<f64,3>
    Array { data: [1, 2] },// Array<i32,2>
    ];
    }
  • Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    fn print_array<T: std::fmt::Debug, const N: usize>(arr: [T; N]) {
    println!("{:?}", arr);
    }
    fn main() {
    let arr = [1, 2, 3];
    print_array(arr);

    let arr = ["hello", "world"];
    print_array(arr);
    }
  • Example2

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #![allow(incomplete_features)]
    #![feature(generic_const_exprs)]

    fn check_size<T>(val: T)
    where
    Assert<{ core::mem::size_of::<T>() < 768 }>: IsTrue,
    {
    //...
    }

    // 修复 main 函数中的错误
    fn main() {
    check_size([0u8; 767]);
    check_size([0i32; 191]);
    // let a = ["hello你好"; ];
    check_size(["hello你好"; 48]); // size of &str ?
    check_size([(); 0].map(|_| "hello你好".to_string())); // size of String?
    check_size(['中'; 3]); // size of char ?
    }

    pub enum Assert<const CHECK: bool> {}

    pub trait IsTrue {}

    impl IsTrue for Assert<true> {}

trait

  • dyn特征对象 使用前提:对象安全(trait fn 返回类型不为Self或泛型) 返回实现同一个trait的不同类型
    1
    2
    3
    4
    5
    6
    7
    fn random_animal(random_number: f64) -> Box<dyn Animal> {
    if random_number < 0.5 {
    Box::new(Sheep {})
    } else {
    Box::new(Sheep {})
    }
    }
1
2
3
4
5
6
7
fn hatch_a_bird(typ: i32) -> Box<dyn Bird> {
if typ == 1 {
Box::new(Swan)
} else {
Box::new(Duck)
}
}
  • bat Example
    1
    2
    3
    4
    5
    6
    fn static_dispatch<T: Foo>(x: T) {
    println!("static_dispatch: {}", x.method());
    }
    fn dynamic_dispatch(x: &dyn Foo) {
    x.method();
    }
  • 关联类型(语法糖) : 以下两个等价
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    trait Contains {
    type A; // A可以加上trait约束,如type A:Copy+std::fmt::Display;
    type B;
    fn contains(&self, _: &Self::A, _: &Self::B) -> bool;
    fn first(&self) -> i32;
    fn last(&self) -> i32;
    }

    impl Contains for Container {
    type A = i32;
    type B = i32;
    fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
    (&self.0 == number_1) && (&self.1 == number_2)
    }
    fn first(&self) -> i32 { self.0 }
    fn last(&self) -> i32 { self.1 }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
trait Contains<A, B> {
fn contains(&self, _: &A, _: &B) -> bool;
fn first(&self) -> i32;
fn last(&self) -> i32;
}

impl Contains<i32, i32> for Container {
fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
(&self.0 == number_1) && (&self.1 == number_2)
}
fn first(&self) -> i32 {
self.0
}
fn last(&self) -> i32 {
self.1
}
}
  • 默认泛型类型参数: 以下三者等价(Self为默认泛型类型参数)
    1
    2
    3
    impl<T: Sub<Output = T>> Sub<Point<T>> for Point<T> {}
    impl<T: Sub<Output = T>> Sub<Self> for Point<T> {}
    impl<T: Sub<Output = T>> Sub for Point<T> {}
  • 如何调用不同trait下的同名方法?
    1
    2
    3
    4
    5
    // trait AgeWidget{fn get();}
    // struct Form();
    // impl AgeWidget for Form{fn get(){}}
    AgeWidget::get(&form);
    <Form as AgeWidget>::get(&form);
  • 用于数组 let birds: [Box<dyn Bird>; 2] = [Box::new(Duck), Box::new(Swan)];let birds: [&dyn Bird; 2] = [&a, &b];
  • 用于函数参数fn draw_with_ref(x: &dyn Draw){}
    impl Debug for Struct
  • Debug
  • Deref
  • Drop , 手动释放:std::mem::drop(),不可显示调用a.drop()

derive 派生

Supertraits特征继承

1
2
3
trait subTrait: SuperTrait1+SuperTrait2{

}

孤儿原则 TODO

  • PartialEq 部分Eq

Rc