26|阶段实操(3):构建一个简单的KV server-高级trait技巧
该思维导图由 AI 生成,仅供参考
处理 Iterator
- 深入了解
- 翻译
- 解释
- 总结
本文深入介绍了如何构建一个简单的KV server,并重点讲解了高级trait技巧。作者通过实例讲解了如何处理Iterator,并介绍了Rust标准库中的IntoIterator trait。在实现get_iter()方法时,作者使用了IntoIterator trait将数据结构的所有权转移到Iterator中,并对Iterator中的数据进行转换。随后,作者提出了对get_iter()方法的封装,使得Storage trait的实现者只需要提供拥有所有权的Iterator,并对Iterator中的Item类型提供Into<Kvpair>。最后,作者通过构建一个StorageIter并实现Iterator trait来简化get_iter()方法的实现。文章还介绍了如何支持事件通知,通过注册事件处理函数和实现事件通知机制,使得注册的事件处理函数可以得到执行。整体来说,本文内容涵盖了Rust编程中的高级trait技巧和事件通知机制的实现,对于想要深入学习Rust编程的读者具有很高的参考价值。
《陈天 · Rust 编程第一课》,新⼈⾸单¥68
全部留言(8)
- 最新
- 精选
- losuikarocksdb 的实现 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1f4b28ff3fcbdb421a0743d47c7b75c3,rocksdb 需要开启 feature multi-threaded-cf ,然后感觉 trait 约束是不是也要改下?需要带上生命周期,rocksdb 库似乎没有办法拿到所有权的迭代器
作者回复: 嗯,确实如此。非常棒!
2021-12-1933 - losuikaOption 有个 transpose ,可以直接 Option<Result> 到 Result<Option>
作者回复: 对
2021-12-191 - 罗杰哈 昨天终于完成 21,22,今天继续
作者回复: 👍
2021-10-271 - Geek_e2201d陈老师,我尝试把MemTable与SledDb整合到一个Server中,通过config参数来动态选择MemTable还是SledDb。尝试了很久都失败了,编译器提示错误为: 50 | let resp = service_cloned.execute(msg); | ^^^^^^^ method cannot be called on `Service<Box<dyn Storage>>` due to unsatisfied trait bounds ... = note: the following trait bounds were not satisfied: `Box<dyn Storage>: Storage` 我的疑问是Box<dyn Storage>为什么不满足Storage呢? server.rs代码如下: use anyhow::Result; use async_prost::AsyncProstStream; use futures::prelude::*; use kv::{CommandRequest, CommandResponse, MemTable, SledDb, Service, Storage}; use tokio::net::TcpListener; use kv::service::ServiceInner; use tracing::info; use clap::{Parser, ArgEnum}; #[derive(Parser)] #[clap(name = "kv server")] struct Cli { #[clap(arg_enum, long, short, default_value="memory")] storage: StorageType, #[clap(long, short='d', default_value="./sled")] sled_dir: String, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ArgEnum)] enum StorageType { Memory, Sled, } #[tokio::main] async fn main() -> Result<()> { tracing_subscriber::fmt::init(); let args: Cli = Cli::parse(); let addr = "127.0.0.1:9527"; let listener = TcpListener::bind(addr).await?; info!("Start listening on {}", addr); let db : Box<dyn Storage> = match args.storage { StorageType::Memory => Box::new(MemTable::default()), StorageType::Sled => Box::new(SledDb::new(args.sled_dir)), }; let service: Service<Box<dyn Storage>> = ServiceInner::new(db).into(); loop { let (stream, addr) = listener.accept().await?; info!("Client {:?} connected", addr); let service_cloned = service.clone(); tokio::spawn(async move { let mut stream = AsyncProstStream::<_, CommandRequest, CommandResponse, _>::from(stream).for_async(); while let Some(Ok(msg)) = stream.next().await { info!("Got a new command: {:?}", msg); let resp = service_cloned.execute(msg); info!("Response: {:?}", resp); stream.send(resp).await.unwrap(); } info!("Client {:?} disconnected", addr); }); }
作者回复: 如果你使用 trait object,那么你的 service 定义就不需要用 Store trait bound 了,可以这样: pub struct Service { inner: Arc<ServiceInner>, broadcaster: Arc<Broadcaster>, } pub struct ServiceInner { store: Box<dyn Store>, on_received: Vec<fn(&CommandRequest)>, on_executed: Vec<fn(&CommandResponse)>, on_before_send: Vec<fn(&mut CommandResponse)>, on_after_send: Vec<fn()>, }
2022-01-142 - 无常请问老师,设计和架构应该如何学习,有什么推荐的资料吗?
作者回复: 可以看看 Fundamentals of software architecture
2021-12-29 - dva第二题我想到的是,不过这样要改注册函数,看起来怪怪的,不知道老师的方法是什么 pub trait Notify1<Arg,E>{ fn notify(&self,arg:&Arg)->Option<E>; } impl <Arg,E>Notify1<Arg,E>for Vec<fn(&Arg)->Option<E>> { fn notify(&self, arg: &Arg) -> Option<E> { for f in self{ match f(arg){ Some(e)=> return Some(e), _=>{}, } } None } } 第三题和老师写的sleddb差不多,直接加了一些TryFrom,中间遇到没有装llvm clang的错误 “error: failed to run custom build command for `librocksdb-sys ...” 还有起名字 rocksdb和包名冲突。写这个扩展有个非常深的体会就是,编译器提示真好。
作者回复: 👍 第二题可以看 github repo 下这章的代码
2021-11-262 - bestgopher我们服务是异步的,但是sled读取文件没看到异步操作,这样是否有问题呢?2022-06-11
- Alvin老师 跟着课程的代码实现过程发现最后持久化存储这边会报个错 the trait `From<&[u8]>` is not implemented for `abi::Value`2022-04-164