Macro

Macro和function的区别 Rust提供了一个功能非常强大的宏体系,通过这些宏,我们可以很方便的进行元编程。Rust 中的宏有点类似于函数。它们跟函数还是有很大的区别的:

1.宏以感叹号 (!) 结尾。

2.宏在编译时并不会生成一个函数调用,而是直接对宏的源代码进行展开(代替我们手工输入这部分代码)。这个和C语言中宏是一样的。从某些方面说,我们可以将宏理解为函数的加强版。

3.function必须声明函数参数的数量和类型。宏可以接受数量可变的参数:我们可以用一个参数或println!(“hello {}”, name)带有两个参数。此外,宏在编译器解释代码的含义之前被展开,因此,例如,宏可以在给定类型上实现特征。函数不能,因为它是在运行时调用的,而trait需要在编译时实现。

4.实现宏而不是函数的缺点是,宏定义比函数定义更复杂,因为您正在编写“编写Rust代码的Rust代码”。由于这种间接性,宏定义通常比函数定义更难阅读、理解和维护。

5.宏和函数之间的另一个重要区别是,在文件中调用宏之前,必须定义宏或将它们引入作用域,而函数可以在任何地方定义和调用。

micro println!() 中括号 {} 是占位符,在标准输出里面插入值。其他的特殊字符的转义跟C一样,都是使用反斜杠开头的。参数的格式化占位符:简单类型使用{}.

  • {} 实现fmt::Display: Uses the {} marker. Format text in a more elegant, user friendly fashion.
fn main() {
    let a = 12;
    println!("a is {}", a);
}
 
let x = &1i8;
println!("{}",x);
println!("a is {}, a again is {}", x, x);
println!("a is {0}, a again is {0}", x);
println!("{{}}, {{ , }}");             // 输出中括号
println!("{:p}",x);                    // 内存地址
println!("{:.2}%", 12.345);            // 保留两位小数
 
 
  • {:?} && {:#?} 实现fmt::Debug: Uses the {:?} marker. Format text for debugging purposes.
#[derive(Debug)]
enum Book {
    Papery,
    Electronic,
}
 
fn main() {
    let book = Book::Papery;
    println!("{:?}",book);
}
 
  • 多个占位符的情况 println!(“{1:?} {0:?} is the {actor:?} name.”, “Slater”, “Christian”, actor=“actor’s”);

  • {:p} 实现stdfmtPointer; 类型的变量,打印其内存地址。

micro panic!() 不可恢复的错误一定会导致程序受到致命的打击而终止运行。

fn main() {
    panic!("error occured");
    println!("Hello, Rust");
}
 

使用环境变量 RUST_BACKTRACE 在Winodws环境中默认使用的终端命令行是 Powershell $env:RUST_BACKTRACE=1 ; cargo run 如果你使用的是 Linux 或 macOS 等 UNIX 系统,一般情况下默认使用的是 bash 命令行,请使用以下命令: RUST_BACKTRACE=1 cargo run 回溯是不可恢复错误的另一种处理方式,它会展开运行的栈并输出所有的信息,然后程序依然会退出。 RUST_BACKTRACE=full micro todo!() 占位符,可以让方法暂时通过编译,后期再补内部代码。

fn get_book(book: &Book) -> Option<String> {
    todo!() // todo means "I will do it later, please be quiet"
}
 
fn delete_book(book: Book) -> Result<(), String> {
    todo!()
}
 

micro format!()

// 格式化
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);
 
// 拼接字符串
let both = format!("{}:{}", ip, port)
 

micro Display

// 使用 use 关键字引入包,让他可以被访问
use std::fmt;
// 定义一个 tuple struct
struct Structure(i32);
// 手动实现 fmt 这个方法
impl fmt::Display for Structure {
    // &self 是对自己的引用。
    // f 是可变化的输出流。
    // 返回 fmt::Result ,表示操作是成功还是失败。
    // 请注意,write! 的语法与 println! 非常相似。
    fn fmt(&self, f: &mut fmt==Formatter) -> fmt==Result {
        write!(f, "{}", self.0)
    }
}
 
fn main() {
    println!("{}",Structure(100));
}
 
 

micro Debug 调试中,完整地显示出一个结构体实例是非常有用的。但如果我们手动的书写一个格式会非常的不方便。所以 Rust 提供了一个方便地输出一整个结构体的方法:

/// 导入调试库 #[derive(Debug)] 
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}
 
fn main() {
    let rect1 = Rectangle { width: 30, height: 50 };
    /// 在 println 和 print 宏中就可以用 {:?} 占位符输出一整个结构体
    println!("rect1 is {:?}", rect1);
    /// 属性较多的话可以使用另一个占位符 {:#?} 。
    println!("rect1 is {:#?}", rect1);
}

stdcollectionHashMap use stdcollectionsHashMap;

fn main() { let mut map = HashMap::new(); // 插入值,存在会覆盖 map.insert(“color”,“yellow”); map.insert(“size”,“100”);

// 插入值,存在就跳过
map.entry("color").or_insert("red");

// get 返回的是Option,注意panic
println!("{}",map.get("color").unwrap());

// iterator 返回的是tuple
for p in map.iter(){
    println!("{:?}",p)
}

// 在确定存在某 key 的情况下修改其值
if let Some(x) = map.get_mut("color") {
    *x = "blue";
}

}