如果项目是一个可执行文件,建议将Cargo.lock 文件上传到git上,让其他开发者与你保持同样的开发环境,如果是一个普通的库不需要将Cargo.lock 文件上传
println!()
元编程 #[derive] 属性
能够减少大量编写和维护代码功能十分有效,比如println! 宏中内部实现调用底层io::std::out 将这些使用固定格式定义出来后,统一成模板 抽象出来。macro_rules!
来定义宏 比如以vec! 为实例e// 声明宏
#[macro_export] // 使用这个注解说明宏是可用的,没有此注解说明宏无法被引用
macro_rules! vec { // macro_rules!, 宏开始宏定义,所定义的宏并不带感叹号
// vec! 宏结构与 match 表达式结构类似 单边模式($($x:expr), *),更加复杂有多个单边模式
($($x:expr ), *) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)* // 上边单边模式匹配的expr ,内部不断push
temp_vec
}
};
}
// 单向模式结构: 一对扩韩包含整个模式, 接下来是$, 后跟一对括号,捕获符合括号内模式 $()内 $x:expr ,其匹配Rust任意表达式并将其记录是 $x, h后面的* 表示匹配一个或者多个 其实说白了单向模式结构是一个正则表达式,内部结构中有其相关的表达式:
{
let mut temp_vec = Vec::new();
temp_vec.push(1);
temp_vec.push(2);
temp_vec.push(3);
temp_vec
}
#[route(GET, "/")]
创建一个route的属性用于注解web应用程序框架是例子: 写一个自定义派生宏,类似于接口让用户自己写具体实现
// 传统的方式 使用 trait结合代码 实现
pub trait HelloMacro {
fn hello_macro(); // 有默认实现,用户使用自定义宏实现具体内容
}
struct Pancakes;
impl HelloMacro for Pancakes{
fn hello_macro() {
println!("Hello, Macro! My name is Pancakes!");
}
}
fn main(){
Pancakes::hello_macro();
}
如上所示代码中我们借助trait 接口方式,有个缺点任何使用 hello_macro方法 我都要写其具体实现,有没有一种方式类似于@GettMaiing一样 我只需要进行注解配置 就可以让代码进行使用,此种过程宏类似于JAVA中注解
rust 中没有反射能力, 需要代码在编译时候生成代码的宏
写过程宏中注意点:
1. 过程宏必须要要是属于自己的包 在当前项目中 新建一个包cargo new hello_marcro_derive --lib
2. 什么刚才创建的包是过程宏包,对Cargo.tom配置如下
[lib]
proc-macro = true
[dependencies]
syn = "1.0"
quote = "1.0"
3. 添加宏定义的的同样代码,这些同样代码对自定义宏的设定 表示自定义是宏 类似JAVA中自定义注解一些配置
// 添加大多数宏的所需要代码
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast = syn::parse(input).unwrap();
// Build the trait implementation
impl_hello_macro(&ast)
}
proc_macro包: 是编译器读取和操作我们Rust代码的API
syn: 将字符串中rust代码解析成一个我们可以操作的数据结构
quote: 将解析的数据结构转回Rust代码
当用户在一个类型指定#[derive(HelloMacro)] 时候,hello_macro_derive 函数将会被调用。原因在于我们已经使用 proc_macro_derive 及其指定名称对 hello_macro_derive 函数进行了注解:HelloMacro ,其匹配到 trait 名,这是大多数过程宏遵循的习惯。
首次进行引入代码如下的二进制结构
pancakes: 包路径下面
Cargo.toml 引入当前其他包路径
[package]
name = "pancakes"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
hello_macro = { path = "../hello_macro" }
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
-- main.rs
use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;
#[derive(HelloMacro)]
struct Pancakes;
fn main() {
Pancakes::hello_macro();
}
hello_macro/lib.rs
pub trait HelloMacro {
fn hello_macro();
}
hello_macro_derive/lib.rs 过程宏定义 具体类似JAVA中自定义的注解
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast = syn::parse(input).unwrap();
// Build the trait implementation
impl_hello_macro(&ast)
}
fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}!", stringify!(#name));
}
}
};
gen.into()
}
[package]
name = "hello_macro_derive"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
syn = "1.0"
quote = "1.0"
rust 使用Result 类型处理 成功和失败时候返回值类型
enum Result<T, E> {
Ok(T),
Err(E),
}
在错误传播过程中 rust 使用?
进行对错误机制的处理
如下所示?运算符会将OK中值返回给变量f, 如果出现了错误,?运算符会提早返回整个函数并将Err值传播给调用, ?之后直接使用调用链形式进一步缩短代码
let mut f = File::open("hello.txt")?;
? 功能与使用match 一样 是对match的简写
服务器代码:
服务运行不会停止,一直运行 加入loop 循环
use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::thread;
use std::time;
fn handle_client(mut stream: TcpStream, wait_time: u64) -> std::io::Result<()> {
let mut buf = [0; 512];
loop {
let bytes_read = stream.read(&mut buf)?;
if bytes_read == 0 {
return Ok(());
}
thread::sleep(time::Duration::from_secs(wait_time));
stream.write(&buf[..bytes_read])?;
stream.write(&("\n".as_bytes()))?;
}
}
fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:8080")?;
for stream in listener.incoming() {
handle_client(stream?, 3)?;
}
Ok(())
}
客户端:
客户端内使用 线程池 join 链接不同服务器
// 客户端
use std::net::TcpStream;
use std::io::{prelude::*, BufReader, Write};
use std::str;
// use std::thread;
use futures::join;
use futures::executor;
fn use_server(server: &str, port: u16, content: &str) -> std::io::Result<()> {
let mut stream = TcpStream::connect((server, port))?;
let _ = stream.write(content.as_bytes())?;
// 读取服务器中数据
let mut reader = BufReader::new(&stream);
let mut buffer: Vec<u8> = Vec::new();
reader.read_until(b'\n', &mut buffer)?;
println!("recv from server: {} ", str::from_utf8(&buffer).unwrap());
Ok(())
}
async fn async_use_server(server: &str, port: u16, content: &str) {
use_server(server, port, content).unwrap();
}
async fn use_all_server() {
let f1 = async_use_server("127.0.0.1", 8080, "use server1 download 127.0.0.1:8080");
// let f2 = async_use_server("127.0.0.1", 8081, "use server2 download 127.0.0.1:8081");
join!(f1);
}
fn main() -> std::io::Result<()> {
// 开启异步服务
let f = use_all_server();
executor::block_on(f);
Ok(())
}
不要通过共享内存来通讯,通过通讯来共享内存
,因此rust实现消息传递并发工具 channel.use std::sync::mpsc;
use std::thread;
fn main() {
// mpsc 是多个生产者,单个消费者
let (tx, rx) = mpsc::channel();
// 子线程发布消息主线程接收 ,move关键字 强制闭包获取 父参数的所有权
thread::spawn(move || {
let val = String::from("Hi");
tx.send(val).unwrap();
// 在线程发送完毕后不能使用val 所有权已经消失了
});
// recv() 阻塞方法,try_recv()费阻塞
let received = rx.recv().unwrap();
println!("Got: {}", received);
}
// 多个发送者 一个消费者
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
// --snip--
let (tx, rx) = mpsc::channel();
let tx1 = tx.clone();
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in vals {
tx1.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
thread::spawn(move || {
let vals = vec![
String::from("more"),
String::from("messages"),
String::from("for"),
String::from("you"),
];
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
for received in rx {
println!("Got: {}", received);
}
// --snip--
}
在某种程度上,任何编程语言的通道d都类似有所有权的概念,一个值传送到通道后, 将无法在使用这个值
共享内存拥有多所有权,多个内存同时访问内存地址,因此保证有消息 必须使用互斥器mutex 锁的概念,比如Java中就是使用mutex防止数据竞争(尝试使用锁,使用完成后记得释放)。 rust得意于类型系统所有权,不需要类似Java 自动释放锁
Mutex 的API
use std::sync::Mutex;
fn main() {
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num = 6;// rust 所有权的概念 自动释放锁
}
println!("m = {:?}", m);
}
use std::sync::Mutex;
use std::thread;
fn main() {
let counter = Mutex::new(0);
let mut handles = vec![];
for _ in 0..10 {
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
cargo run
Compiling shared-state v0.1.0 (file:///projects/shared-state)
error[E0382]: use of moved value: `counter`
--> src/main.rs:9:36
|
5 | let counter = Mutex::new(0);
| ------- move occurs because `counter` has type `Mutex<i32>`, which does not implement the `Copy` trait
...
9 | let handle = thread::spawn(move || {
| ^^^^^^^ value moved into closure here, in previous iteration of loop
10 | let mut num = counter.lock().unwrap();
| ------- use occurs due to use in closure
明显编译不通过: 不能用Counter所有权移动到多个线程中
use std::rc::Rc;
use std::sync::Mutex;
use std::thread;
fn main() {
let counter = Rc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Rc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
编译还是出现错误,Rc<T> 无法保证修改技术操作时候不被其他线程打断
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}