设计感很强的中文网站,货运代理东莞网站建设,如今做那些网站能致富,广西冶金建设公司网站文章目录 不安全的rust解引用裸指针裸指针与引用和智能指针的区别裸指针使用解引用运算符 *#xff0c;这需要一个 unsafe 块调用不安全函数或方法在不安全的代码之上构建一个安全的抽象层 使用 extern 函数调用外部代码rust调用C语言函数rust接口被C语言程序调用 访问或修改可… 文章目录 不安全的rust解引用裸指针裸指针与引用和智能指针的区别裸指针使用解引用运算符 *这需要一个 unsafe 块调用不安全函数或方法在不安全的代码之上构建一个安全的抽象层 使用 extern 函数调用外部代码rust调用C语言函数rust接口被C语言程序调用 访问或修改可变静态变量静态变量可变静态变量 实现不安全 trait访问联合体中的字段 高级trait关联类型在 trait 定义中指定占位符类型使用关联类型针对一个类型的实现使用泛型针对多个类型的实现 默认泛型类型参数和运算符重载重载标准库Add操作符实现Add特征可以让Point支持Add操作符 调用同名方法如果是特征和结构体类型定义的都是关联函数情况则不同 超特征Super trait新类型newtype 模式用于在外部类型上实现外部 trait新类型可以提供轻量级的封装机制创建类型别名从不返回的 never typecontinuepanic!有着 ! 类型的表达式是 loop 动态类型DSTstr特征是动态长度类型的编译时借助Sized trait 高级函数函数指针fn(x)-y三种闭包类型FnFnMutFnOnce元组结构体和元组结构体成员返回一个闭包 宏声明Declarative宏过程Procedural宏如何编写自定义 derive 宏只适用于结构体和枚举类属性宏适用于结构体、枚举、函数类函数宏 参考 不安全的rust
不安全的rust提供的能力如下
解引用裸指针调用不安全的函数或方法访问或修改可变静态变量实现不安全 trait访问 union 的字段
unsafe 并不会关闭借用检查器或禁用任何其他 Rust 安全检查如果在不安全代码中使用引用它仍会被检查。
unsafe 关键字只是提供了那五个不会被编译器检查内存安全的功能。你仍然能在不安全块中获得某种程度的安全。
解引用裸指针
裸指针与引用和智能指针的区别
允许忽略借用规则可以同时拥有不可变和可变的指针或多个指向相同位置的可变指针不保证指向有效的内存允许为空不能实现任何自动清理功能
eg如何从引用同时创建不可变和可变裸指针
#![allow(unused)]
fn main() {let mut num 5;let r1 num as *const i32; //不可变裸指针let r2 mut num as *mut i32; //可变裸指针
}
裸指针使用解引用运算符 *这需要一个 unsafe 块
#![allow(unused)]
fn main() {let mut num 5;let r1 num as *const i32;let r2 mut num as *mut i32;unsafe {println!(r1 is: {}, *r1);println!(r2 is: {}, *r2);}
}
编译
▶ cargo runBlocking waiting for file lock on build directoryCompiling bobo v0.1.0 (/home/wangji/code/rust/bobo)Finished dev profile [unoptimized debuginfo] target(s) in 9.83sRunning target/debug/bobo
r1 is: 5
r2 is: 5调用不安全函数或方法
#![allow(unused)]
fn main() {unsafe fn dangerous() {}// 必须在一个单独的 unsafe 块中调用 dangerous 函数unsafe {dangerous();}
}
在不安全的代码之上构建一个安全的抽象层
问题代码
#![allow(unused)]
fn main() {let mut v vec![1, 2, 3, 4, 5, 6];let r mut v[..];let (a, b) r.split_at_mut(3);assert_eq!(a, mut [1, 2, 3]);assert_eq!(b, mut [4, 5, 6]);
}fn split_at_mut(slice: mut [i32], mid: usize) - (mut [i32], mut [i32]) {let len slice.len();assert!(mid len);// 不能对切片进行两次可变借用(mut slice[..mid], mut slice[mid..])
}
使用slice处理裸指针
#![allow(unused)]
fn main() {let mut v vec![1, 2, 3, 4, 5, 6];let r mut v[..];let (a, b) r.split_at_mut(3);assert_eq!(a, mut [1, 2, 3]);assert_eq!(b, mut [4, 5, 6]);
}use std::slice;
// 切片slice包括指向某个数据的指针和数据的长度
fn split_at_mut(slice: mut [i32], mid: usize) - (mut [i32], mut [i32]) {let len slice.len();let ptr slice.as_mut_ptr(); // 返回指向slice中第一个元素的裸指针assert!(mid len);unsafe {(slice::from_raw_parts_mut(ptr, mid),slice::from_raw_parts_mut(ptr.add(mid), len - mid),)}
}
使用 extern 函数调用外部代码
extern有助于创建和使用 外部函数接口Foreign Function Interface FFI。外部函数接口是一个编程语言用以定义函数的方式其允许不同外部编程语言调用这些函数。
如何集成 C 标准库中的 abs 函数。
rust调用C语言函数
extern C {fn abs(input: i32) - i32;
}fn main() {unsafe {println!(Absolute value of -3 according to C: {}, abs(-3));}
}rust接口被C语言程序调用
还需增加 #[no_mangle] 标注来告诉 Rust 编译器不要 mangle 此函数的名称。Mangling 发生于当编译器将我们指定的函数名修改为不同的名称时这会增加用于其他编译过程的额外信息不过会使其名称更难以阅读。
每一个编程语言的编译器都会以稍微不同的方式 mangle 函数名所以为了使 Rust 函数能在其他语言中指定必须禁用 Rust 编译器的 name mangling。
#![allow(unused)]
fn main() {#[no_mangle]pub extern C fn call_from_c() {println!(Just called a Rust function from C!);}
}
访问或修改可变静态变量
静态变量
rust中全局变量就是静态变量
static HELLO_WORLD: str Hello, world!;fn main() {println!(name is: {}, HELLO_WORLD);
}
可变静态变量
访问不可变静态变量必须使用unsafe{}包起来
static mut COUNTER: u32 0;fn add_to_count(inc: u32) {unsafe {COUNTER inc;}
}fn main() {add_to_count(3);unsafe {println!(COUNTER: {}, COUNTER);}
}
实现不安全 trait
#![allow(unused)]
fn main() {unsafe trait Foo {// methods go here}unsafe impl Foo for i32 {// method implementations go here}
}
访问联合体中的字段
高级trait
关联类型在 trait 定义中指定占位符类型
关联类型associated types是一个将类型占位符与 trait 相关联的方式这样 trait 的方法签名中就可以使用这些占位符类型。trait 的实现者会针对特定的实现在这个类型的位置指定相应的具体类型。如此可以定义一个使用多种类型的 trait直到实现此 trait 时都无需知道这些类型具体是什么。
使用关联类型针对一个类型的实现
#![allow(unused)]
fn main() {}pub trait Iterator {//一个带有关联类型的 trait 的例子是标准库提供的 Iterator trait。它有一个叫做 Item 的关联类型来替代遍历的值的类型。type Item;fn next(mut self) - OptionSelf::Item;
}
struct Counter {}
impl Iterator for Counter {type Item u32;fn next(mut self) - OptionSelf::Item {// --snip--Some(0)}
}// 报错!!
impl Iterator for Counter {type Item u16;fn next(mut self) - OptionSelf::Item {// --snip--Some(0)}
}
使用泛型针对多个类型的实现
使用泛型修改可以支持多个类型
#![allow(unused)]
fn main() {}pub trait IteratorT {fn next(mut self) - OptionT;
}
struct Counter {}
impl Iteratoru32 for Counter {fn next(mut self) - Optionu32 {// --snip--Some(0)}
}impl Iteratoru16 for Counter {fn next(mut self) - Optionu16 {// --snip--Some(0)}
}
默认泛型类型参数和运算符重载
重载标准库Add操作符实现Add特征可以让Point支持Add操作符
use std::ops::Add;#[derive(Debug, PartialEq)]
struct Point {x: i32,y: i32,
}impl Add for Point {type Output Point;fn add(self, other: Point) - Point {Point {x: self.x other.x,y: self.y other.y,}}
}fn main() {assert_eq!(Point { x: 1, y: 0 } Point { x: 2, y: 3 },Point { x: 3, y: 3 });
}
rust标准库Add特征源码
rhsright hand side表示右手边Self表示实现Add特征的类型 比较陌生的部分是尖括号中的 RHSSelf这个语法叫做 默认类型参数default type parameters RHS 是一个泛型类型参数“right hand side” 的缩写它用于定义 add 方法中的 rhs 参数。如果实现 Add trait 时不指定 RHS 的具体类型RHS 的类型将是默认的 Self 类型也就是在其上实现 Add 的类型。 注意如果想加的类型不同那么泛型则需要指定
#![allow(unused)]
fn main() {}use std::ops::Add;struct Millimeters(u32);
struct Meters(u32);impl AddMeters for Millimeters {type Output Millimeters;fn add(self, other: Meters) - Millimeters {Millimeters(self.0 (other.0 * 1000))}
}默认参数类型主要用于如下两个方面
扩展类型而不破坏现有代码。在大部分用户都不需要的特定情况进行自定义。
调用同名方法
rust允许特征拥有同名的方法可以让一个类型同时实现这两个特征也可以让一个类型拥有和特征同名的方法
trait Pilot {fn fly(self);
}trait Wizard {fn fly(self);
}struct Human;impl Pilot for Human {fn fly(self) {println!(This is your captain speaking.);}
}impl Wizard for Human {fn fly(self) {println!(Up!);}
}impl Human {fn fly(self) {println!(*waving arms furiously*);}
}fn main() {let person Human;//显式调用特征的方法Pilot::fly(person);Wizard::fly(person);person.fly();
}
编译
cargo runCompiling blog v0.1.0 (/home/wangji/installer/rust/bobo/smartPtr)Finished dev profile [unoptimized debuginfo] target(s) in 6.29sRunning target/debug/blog
This is your captain speaking.
Up!
*waving arms furiously*如果是特征和结构体类型定义的都是关联函数情况则不同
trait Animal {fn baby_name() - String;
}struct Dog;impl Dog {fn baby_name() - String {String::from(Spot)}
}impl Animal for Dog {fn baby_name() - String {String::from(puppy)}
}fn main() {println!(A baby dog is called a {}, Dog::baby_name());//调用实现Animal trait的baby_name函数println!(A baby dog is called a {}, Dog as Animal::baby_name());
}
编译
cargo runCompiling blog v0.1.0 (/home/wangji/installer/rust/bobo/smartPtr)Finished dev profile [unoptimized debuginfo] target(s) in 0.33sRunning target/debug/blog
A baby dog is called a Spot
A baby dog is called a puppy超特征Super trait
一个特征依赖另外一个特征被依赖的特征就称之为超特征。
问题代码
#![allow(unused)]
fn main() {}trait OutlinePrint {fn outline_print(self) {// 不知道是否实现了to_stringto_string特征是在dispaly特征中定义的let output self.to_string();let len output.len();println!({}, *.repeat(len 4));println!(*{}*, .repeat(len 2));println!(* {} *, output);println!(*{}*, .repeat(len 2));println!({}, *.repeat(len 4));}
}解决办法继承超特征fmt::Display特征
#![allow(unused)]
fn main() {}use std::fmt;trait OutlinePrint: fmt::Display {fn outline_print(self) {// Display 特征中包含to_string()方法let output self.to_string();let len output.len();println!({}, *.repeat(len 4));println!(*{}*, .repeat(len 2));println!(* {} *, output);println!(*{}*, .repeat(len 2));println!({}, *.repeat(len 4));}
}
#![allow(unused)]
fn main() {}use std::fmt;// 有时我们可能会需要某个 trait 使用另一个 trait 的功能
// 在这种情况下需要能够依赖相关的 trait 也被实现。这个所需的 trait 是我们实现的 trait 的 父超 traitsupertrait
trait OutlinePrint: fmt::Display {fn outline_print(self) {// Display 特征中包含to_string()方法//因为指定了 OutlinePrint 需要 Display trait则可以在 outline_print 中使用 to_string 其会为任何实现 Display 的类型自动实现let output self.to_string();let len output.len();println!({}, *.repeat(len 4));println!(*{}*, .repeat(len 2));println!(* {} *, output);println!(*{}*, .repeat(len 2));println!({}, *.repeat(len 4));}
}struct Point {x: i32,y: i32,
}//如果要在实现 OutlinePrint 特征的 struct 中调用 outline_print则必须实现 fmt::Display trait
impl OutlinePrint for Point {}impl fmt::Display for Point {fn fmt(self, f: mut fmt::Formatter) - fmt::Result {write!(f, ({}, {}), self.x, self.y)}
}新类型newtype 模式用于在外部类型上实现外部 trait
孤儿规则orphan rule它说明只要 trait 或类型两者至少有一个在你的crate中定义的时候呢你才能让你的类型实现你的特征。 如果特征和类型都不是你的crate中定义的而你仍然想要你的类型实现你的特征那就需要新类型模式 例如如果想要在 VecT 上实现 Display而孤儿规则阻止我们直接这么做因为 Display trait 和 VecT 都定义于我们的 crate 之外。
可以创建一个包含 VecT 实例的 Wrapper 结构体接着可以如示例 19-31 那样在 Wrapper 上实现 Display 并使用 VecT 的值
use std::fmt;// 如果想在Vec上实现Dispaly特征但是Vec和Display特征都不是在这个模块定义的通过创建一个Wrapper封装类型绕过孤儿规则
// Wrapper是在我们crate中定义的所以可以正常实现Display特征
struct Wrapper(VecString);impl fmt::Display for Wrapper {fn fmt(self, f: mut fmt::Formatter) - fmt::Result {write!(f, [{}], self.0.join(, ))}
}fn main() {let w Wrapper(vec![String::from(hello), String::from(world)]);println!(w {}, w);
}
新类型可以提供轻量级的封装机制
定义一些有语义的元组结构体的类型比起原始类型更加有语义
struct Age(u32);struct ID(u32);fn main()
{}创建类型别名
#![allow(unused)]
fn main() {type Kilometers i32;let x: i32 5;let y: Kilometers 5;println!(x y {}, x y);
}
#![allow(unused)]
fn main() {type Thunk Boxdyn Fn() Send static;let f: Thunk Box::new(|| println!(hi));fn takes_long_type(f: Thunk) {// --snip--}fn returns_long_type() - Thunk {// --snip--Box::new(|| ())}
}
从不返回的 never type
这个名字描述了它的作用在函数从不返回的时候充当返回值
continue
#![allow(unused)]
fn main() {// match 的分支必须返回相同的类型。/*** 特殊情况continue 的值是 !。也就是说当 Rust 要计算 guess 的类型时它查看这两个分支。* 前者是 u32 值而后者是 ! 值。因为 ! 并没有一个值Rust 决定 guess 的类型是 u32。** 描述 ! 的行为的正式方式是 never type 可以强转为任何其他类型。允许 match 的分支以 continue 结束是* 因为 continue 并不真正返回一个值相反它把控制权交回上层循环所以在 Err 的情况事实上并未对 guess 赋值。*/let guess 3;loop {let guess: u32 match guess.trim().parse() {Ok(num) num,Err(_) continue,};break;}
}
panic!
/*** Rust 知道 val 是 T 类型panic! 是 ! 类型所以整个 match 表达式的结果是 T 类型。* 这能工作是因为 panic! 并不产生一个值它会终止程序*/
implT OptionT {pub fn unwrap(self) - T {match self {Some(val) val,None panic!(called Option::unwrap() on a None value),}}
}
有着 ! 类型的表达式是 loop
print!(forever );loop {print!(and ever );
}
动态类型DST
str
// str。没错不是 str
// 解决办法可以将 str 与所有类型的指针结合比如 Boxstr 或 Rcstrstr
let s1: str Hello there!;
let s2: str Hows it going?;// T 是一个储存了 T 所在的内存位置的单个值str 则是 两个 值str 的地址和其长度。
// 地址和长度的类型都是usize
let s1: str Hello there!;
let s2: str Hows it going?;特征是动态长度类型的编译时借助Sized trait
为了处理 DSTRust 有一个特定的 trait 来确定一个类型的大小是否在编译时可知这就是 Sized trait。这个 trait 自动为编译器在编译时就知道其大小的类型实现
fn genericT(t: T) {// --snip--
}// 自动转成如下所示
fn genericT: Sized(t: T) {// --snip--
}//?Sized 表示T时已知的或者未知的大小只是适用于Sized特征
// 将 t 参数的类型从 T 变为了 T因为其类型可能不是 Sized 的所以需要将其置于某种指针之后。
fn genericT: ?Sized(t: T) {// --snip--
}
高级函数
函数指针fn(x)-y
函数的类型是 fn 使用小写的 “f” 以免与 Fn 闭包 trait 相混淆。fn 被称为 函数指针function pointer。
fn add_one(x: i32) - i32 {x 1
}fn do_twice(f: fn(i32) - i32, arg: i32) - i32 {f(arg) f(arg)
}fn main() {let answer do_twice(add_one, 5);println!(The answer is: {}, answer);
}编译
cargo runBlocking waiting for file lock on build directoryCompiling blog v0.1.0 (/home/wangji/installer/rust/bobo/smartPtr)Finished dev profile [unoptimized debuginfo] target(s) in 9.69sRunning target/debug/blog
The answer is: 12三种闭包类型FnFnMutFnOnce
Fn以不可变形式捕获外部变量
FnMut以可变的形式捕获外部变量
FnOnce以转移所有权的方式捕获外部变量
闭包作为参数的好处既可以传入参数也可以传入函数指针
fn add_one(x: i32) - i32 {x 1
}fn do_twiceT(f: T, arg: i32) - i32
whereT: Fn(i32) - i32,
{f(arg) f(arg)
}fn main() {let answer do_twice(add_one, 5);println!(The answer is: {}, answer);
}
#![allow(unused)]
fn main() {let list_of_numbers vec![1, 2, 3];let list_of_strings: VecString list_of_numbers.iter().map(|i| i.to_string()).collect();//使用函数指针替代// 看ToString::to_string)源码可知任何实现Display特征的类型都会实现ToString特征也就可以调用to_string()方法let list_of_strings: VecString list_of_numbers.iter().map(ToString::to_string).collect();
}
元组结构体和元组结构体成员
#![allow(unused)]
fn main() {enum Status {// 这些项使用 () 作为初始化语法这看起来就像函数调用//同时它们确实被实现为返回由参数构造的实例的函数。它们也被称为实现了闭包 trait 的函数指针Value(u32),Stop,}// Status::Value当作一个函数指针入参就是u32类型返回值是Status类型let list_of_statuses: VecStatus (0u32..20).map(Status::Value).collect();// 使用闭包初始化 Status::Valuelet list_of_statuses: VecStatus (0u32..20).map(|x| Status::Value(x)) // 闭包.collect();
}
返回一个闭包
可以的
#![allow(unused)]
fn main() {}fn returns_closure() - impl Fn(i32) - i32 {|x| x 1
}
错误代码
由于闭包捕获 x并且 x 可能会在不同的分支中被捕获为不同的值Rust 必须确保闭包的生命周期与 x 的生命周期一致而这需要更精确的类型推断。
#![allow(unused)]
fn main() {}fn returns_closure(x: i32) - impl Fn(i32) - i32 {if x 0 {move |y| x y} else {move |y| x - y}
}
解决办法使用特征对象进行动态派遣
#![allow(unused)]
fn main() {}fn returns_closure(x: i32) - Boxdyn Fn(i32) - i32 {if x 0 {Box::new(move |y| x y)} else {Box::new(move |y| x - y)}
}
动态派遣 (dyn Fn(i32) - i32)
使用 dyn Fn(i32) - i32 是 Rust 中的 动态特征对象动态派遣trait object它允许在运行时确定闭包的类型而不需要在编译时确定所有具体的类型。在你的原始代码中impl Fn(i32) - i32 是一个 静态派遣 类型它要求编译器在编译时推断出闭包的具体类型。由于你在 if 和 else 分支中返回不同的闭包这会使得 Rust 无法统一推断返回的闭包类型因此需要用动态特征对象来解决。 在原始的代码中当使用 impl Fn(i32) - i32 时Rust 需要在编译时确定返回的闭包类型。但由于你在 if 和 else 分支中创建了两种不同的闭包它们的类型会有所不同导致 Rust 无法推导出统一的返回类型。 通过使用 Boxdyn Fn(i32) - i32你将返回值的类型改成了 动态特征对象这意味着 Rust 在编译时不再需要知道闭包的具体类型而是通过运行时的动态派遣来决定如何调用闭包。此外闭包被存储在堆上通过 Box因此它们可以拥有不同的大小而 Rust 不需要在栈上存储这些不同大小的闭包。 宏
声明Declarative宏
利用模式匹配专门匹配代码进行代码替换
比较难可以看The Little Book of Rust Macros
// #[macro_export] 宏导出注解只要将定义了宏的 crate 引入作用域宏就应当是可用的
// 此处有一个单边模式 ( $( $x:expr ),* ) 后跟 以及和模式相关的代码块。如果模式匹配该相关代码块将被执行
// 宏模式所匹配的是 Rust 代码结构而不是值
#[macro_export]
macro_rules! vec {( $( $x:expr ),* ) {{let mut temp_vec Vec::new();$(temp_vec.push($x);)*temp_vec}};
}// 当以 vec![1, 2, 3]; 调用宏时$x 模式与三个表达式 1、2 和 3 进行了三次匹配。
// ( $( $x:expr ),* ) 每次取出一个作为$x的值然后执行相关代码块替换
let mut temp_vec Vec::new();
temp_vec.push(1);
temp_vec.push(2);
temp_vec.push(3);
temp_vec过程Procedural宏
三种 过程Procedural宏
自定义 #[derive] 宏在结构体和枚举上指定通过 derive 属性添加的代码类属性Attribute-like宏定义可用于任意项的自定义属性类函数宏function-like看起来像函数不过作用于作为参数传递的 token
当前的过程Procedural宏必须定义为特殊的crate类型并且要定义在自己的crate中。
过程宏的本质 宏操作的源代码构成了输入 TokenStream宏产生的代码是输出 TokenStream。该函数还附加了一个属性该属性指定我们正在创建过程宏的类型。我们可以在同一个 crate 中拥有多种过程宏。
use proc_macro;#[some_attribute]
pub fn some_name(input: TokenStream) - TokenStream {
}如何编写自定义 derive 宏只适用于结构体和枚举
对于自定义衍生的库crate会库名会加上后缀__derive
发布的仍然需要单独发布所以这个宏的人仍然需要导入每一个crate看main.rs
cargo new hello_macro --libCreating library hello_macro package
note: see more Cargo.toml keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
~/installer/rust/bobo
~/installer/rust/bobo
cd hello_macro/
~/installer/rust/bobo/hello_macro master
cargo new hello_macro_drive --libhello_macro_drive/src/lib.rs
extern crate proc_macro;use crate::proc_macro::TokenStream; //读取和修改rust的代码
use quote::quote; //接受语法树结构然后转成rust代码
use syn; //接受rust代码转成可操作的语法树结构#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) - TokenStream {// 将 Rust 代码解析为语法树以便进行操作let ast syn::parse(input).unwrap(); //解析成语法树// 构建 trait 实现impl_hello_macro(ast) //转化语法树
}
fn impl_hello_macro(ast: syn::DeriveInput) - TokenStream {let name ast.ident;let gen quote! {// #name会被替换成实际的类型名impl HelloMacro for #name {fn hello_macro() {// stringify!(#name)可以将表达式转成字符串于format()!和println!()是不同的println!(Hello, Macro! My name is {}, stringify!(#name));}}};gen.into() //转成TokenStream
}
src/lib.rs
pub trait HelloMacro {fn hello_macro();
}hello_macro_derive/Cargo.toml
[package]
name hello_macro_derive
version 0.1.0
edition 2021[lib]
proc-macro true[dependencies]
syn 1.0
quote 1.0 测试这个宏
use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;#[derive(HelloMacro)]
struct Pancakes;fn main() {Pancakes::hello_macro();
}
Cargo.toml
[package]
name test_orocedural_macros
version 0.1.0
edition 2021[dependencies]
hello_macro { path ../hello_macro }
hello_macro_derive { path ../hello_macro/hello_macro_derive } 编译
cargo runUpdating rsproxy-sparse indexLocking 6 packages to latest compatible versionsAdding hello_macro v0.1.0 (/home/wangji/installer/rust/bobo/hello_macro)Adding hello_macro_derive v0.1.0 (/home/wangji/installer/rust/bobo/hello_macro/hello_macro_derive)Adding proc-macro2 v1.0.89Adding quote v1.0.37Adding syn v1.0.109Adding unicode-ident v1.0.13Compiling proc-macro2 v1.0.89Compiling unicode-ident v1.0.13Compiling syn v1.0.109Compiling hello_macro v0.1.0 (/home/wangji/installer/rust/bobo/hello_macro)Compiling quote v1.0.37Compiling hello_macro_derive v0.1.0 (/home/wangji/installer/rust/bobo/hello_macro/hello_macro_derive)Compiling test_orocedural_macros v0.1.0 (/home/wangji/installer/rust/bobo/test_orocedural_macros)Finished dev profile [unoptimized debuginfo] target(s) in 2.31sRunning target/debug/test_orocedural_macros
Hello, Macro! My name is Pancakes类属性宏适用于结构体、枚举、函数
伪代码
//#[route(GET, /)]会生成代码会将http请求映射到函数index()上
#[route(GET, /)]
fn index() {}// 用过程宏的方式定义这样一个属性和自定义衍生宏的工作方式是类似的
// 这里有两个 TokenStream 类型的参数第一个用于属性内容本身也就是 GET, / 部分。第二个是属性所标记的项
// 在本例中是 fn index() {} 和剩下的函数体。
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) - TokenStream {}
类函数宏
let sql sql!(SELECT * FROM posts WHERE id1);// 与自定义衍生宏很像
// 注意注解使用的是#[proc_macro]
#[proc_macro]
pub fn sql(input: TokenStream) - TokenStream {}参考 第19章编写不安全的Rust代码 高级特征 文章转载自: http://www.morning.jcxyq.cn.gov.cn.jcxyq.cn http://www.morning.gwxwl.cn.gov.cn.gwxwl.cn http://www.morning.dhyqg.cn.gov.cn.dhyqg.cn http://www.morning.rlhgx.cn.gov.cn.rlhgx.cn http://www.morning.dbdmr.cn.gov.cn.dbdmr.cn http://www.morning.ljzgf.cn.gov.cn.ljzgf.cn http://www.morning.kyzja.com.gov.cn.kyzja.com http://www.morning.trwkz.cn.gov.cn.trwkz.cn http://www.morning.cwpny.cn.gov.cn.cwpny.cn http://www.morning.kphyl.cn.gov.cn.kphyl.cn http://www.morning.gmjkn.cn.gov.cn.gmjkn.cn http://www.morning.bktzr.cn.gov.cn.bktzr.cn http://www.morning.sxlrg.cn.gov.cn.sxlrg.cn http://www.morning.xphcg.cn.gov.cn.xphcg.cn http://www.morning.xxiobql.cn.gov.cn.xxiobql.cn http://www.morning.qhmhz.cn.gov.cn.qhmhz.cn http://www.morning.mrgby.cn.gov.cn.mrgby.cn http://www.morning.jnptt.cn.gov.cn.jnptt.cn http://www.morning.lggng.cn.gov.cn.lggng.cn http://www.morning.qxjck.cn.gov.cn.qxjck.cn http://www.morning.htmhl.cn.gov.cn.htmhl.cn http://www.morning.clndl.cn.gov.cn.clndl.cn http://www.morning.rggky.cn.gov.cn.rggky.cn http://www.morning.lsmgl.cn.gov.cn.lsmgl.cn http://www.morning.xbmwm.cn.gov.cn.xbmwm.cn http://www.morning.rkxk.cn.gov.cn.rkxk.cn http://www.morning.wspyb.cn.gov.cn.wspyb.cn http://www.morning.grxbw.cn.gov.cn.grxbw.cn http://www.morning.ryfqj.cn.gov.cn.ryfqj.cn http://www.morning.shinezoneserver.com.gov.cn.shinezoneserver.com http://www.morning.pkdng.cn.gov.cn.pkdng.cn http://www.morning.dqpnd.cn.gov.cn.dqpnd.cn http://www.morning.cjrmf.cn.gov.cn.cjrmf.cn http://www.morning.gqwbl.cn.gov.cn.gqwbl.cn http://www.morning.wdprz.cn.gov.cn.wdprz.cn http://www.morning.srcth.cn.gov.cn.srcth.cn http://www.morning.pftjj.cn.gov.cn.pftjj.cn http://www.morning.tbhlc.cn.gov.cn.tbhlc.cn http://www.morning.ruyuaixuexi.com.gov.cn.ruyuaixuexi.com http://www.morning.mfnjk.cn.gov.cn.mfnjk.cn http://www.morning.jbhhj.cn.gov.cn.jbhhj.cn http://www.morning.fpzz1.cn.gov.cn.fpzz1.cn http://www.morning.kmlmf.cn.gov.cn.kmlmf.cn http://www.morning.ssfq.cn.gov.cn.ssfq.cn http://www.morning.rklgm.cn.gov.cn.rklgm.cn http://www.morning.nkddq.cn.gov.cn.nkddq.cn http://www.morning.khpx.cn.gov.cn.khpx.cn http://www.morning.pzbqm.cn.gov.cn.pzbqm.cn http://www.morning.gkmwk.cn.gov.cn.gkmwk.cn http://www.morning.hfbtt.cn.gov.cn.hfbtt.cn http://www.morning.stpkz.cn.gov.cn.stpkz.cn http://www.morning.tnbas.com.gov.cn.tnbas.com http://www.morning.pqchr.cn.gov.cn.pqchr.cn http://www.morning.nlffl.cn.gov.cn.nlffl.cn http://www.morning.thpzn.cn.gov.cn.thpzn.cn http://www.morning.ksbmx.cn.gov.cn.ksbmx.cn http://www.morning.krrjb.cn.gov.cn.krrjb.cn http://www.morning.nafdmx.cn.gov.cn.nafdmx.cn http://www.morning.swlwf.cn.gov.cn.swlwf.cn http://www.morning.xnflx.cn.gov.cn.xnflx.cn http://www.morning.rkxqh.cn.gov.cn.rkxqh.cn http://www.morning.hryhq.cn.gov.cn.hryhq.cn http://www.morning.qgmwt.cn.gov.cn.qgmwt.cn http://www.morning.znqfc.cn.gov.cn.znqfc.cn http://www.morning.zbmcz.cn.gov.cn.zbmcz.cn http://www.morning.alwpc.cn.gov.cn.alwpc.cn http://www.morning.rbsmm.cn.gov.cn.rbsmm.cn http://www.morning.fmznd.cn.gov.cn.fmznd.cn http://www.morning.myzfz.com.gov.cn.myzfz.com http://www.morning.llmhq.cn.gov.cn.llmhq.cn http://www.morning.pdwny.cn.gov.cn.pdwny.cn http://www.morning.bpmmq.cn.gov.cn.bpmmq.cn http://www.morning.hlfnh.cn.gov.cn.hlfnh.cn http://www.morning.pjqxk.cn.gov.cn.pjqxk.cn http://www.morning.ntcmrn.cn.gov.cn.ntcmrn.cn http://www.morning.yrbhf.cn.gov.cn.yrbhf.cn http://www.morning.dddcfr.cn.gov.cn.dddcfr.cn http://www.morning.cypln.cn.gov.cn.cypln.cn http://www.morning.0small.cn.gov.cn.0small.cn http://www.morning.ggcjf.cn.gov.cn.ggcjf.cn