技术选型,主要是选择市面上主流的框架,看他们的源码是怎么玩的, web 选择的是rocket ,rocket内部的选型是tokio +hyper 所以,我的框架也会是根据tokio+hyper 然后,先看tokio 是怎么用的, 然后再看hyper 怎么嵌入, hyper 是bind tcpListener, 然后围绕tcpListener通过future 封装 request & response , 那跟我之前的框架倒也差不多,唯一的区别的是tcpListener rust 因为borrow 有点麻烦~
2022-06-30
2022-06-24
2022-06-18
2022-06-15
2022-06-13
2022-05-24
2022-05-20
2022-05-23
rust 怎么定义字符串(字符串内部有换行)
https://seekstar.github.io/2021/07/06/rust%E5%A4%9A%E8%A1%8C%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%AD%97%E9%9D%A2%E9%87%8F/
直接原模原样拷贝就行,不需要加 \n
pub const INIT: &'static str = " .__ .__
____ ____ | | | |
_/ ___\\/ __ \\| | | |
\\ \\__\\ ___/| |_| |__
\\___ >___ >____/____/
\\/ \\/\n";
rust 怎么判断类型
rust channel 如何close
rust 如何监听ctrl+c 退出
trait 如何添加lifetime
refcell 调用borrow的时候提示: type annotations needed for &Borrowed
如果trait 用self 作为参数的话,会出现 cant know size compile time ,
如果外层的 self 是个brorrow 的时候, 但是内层的 一个 成员变量的method 为 self,需要ownship的时候, 这个成员变量,可以用refcell来包裹
具体的commit: fbb45b9db8b8d6191fdfb7fae0edf5d287b54c06
pub struct HttpExtension {
server: Arc>,
}
impl NodeExtension for HttpExtension {
fn module(&self) -> CellModule {
HttpModule
}
fn on_start(&mut self, ctx: Arc) -> CellResult<()> {
let s = self.server.take(); // 注意这一行, 直接take 可以获得 ownship
ctx.tokio_runtime.spawn(s.start());
Ok(())
}
}
其实内部就是 mem:replace , 使用的是 server 的default 函数 ,所以一旦使用了,就再也不能使用了,因为是一个default 对象了
refcell 和cell的区别
RefCell
和Cell
的区别在于,Cell
只能用于那么实现了Copy
Trait的类型,其余的类型使用RefCell
,RefCell
让程序在修改变量时必须先获得一个写锁。shaku 同个类型依赖多个vec
rust 宏如何输入string ,既 参数为string 的时候,宏调用的也是string
rust .except 的用法
rust channel 如何send error
rust 一单某个struct 出现了 lifetime,则这个lifetime 很可能会贯穿整个程序(所有相关的代码都会有), 参考这个commit:
rust box trait 可以修改值吗
Rust 当从sync 转为async的时候, 整个过程涉及到的所有的rc 都需要更改为arc ,同时 如果涉及到trait 的时候, async-trait 这个库自身编译时又有限制,返回的future 必须+ Send ,所以这里会有一个问题是,如果整个流程中某个struct 没有实现 send 的话, 则 编译的时候就会过不了,提示: the trait std::marker::Send
is not implemented for dyn futures::Future
https://blog.rust-lang.org/inside-rust/2019/10/11/AsyncAwait-Not-Send-Error-Improvements.html
We now know that an async fn is represented like an enum behind-the-scenes. In synchronous Rust, you'll be used to your types automatically implementing Send when the compiler determines it's appropriate - typically when all of the fields of your type also implement Send. It follows that the enum-like that represents our async fn would implement Send if all of the types in it do.
比如说rust-cell 的这个 commit: 72178c530144d29a751f164510150f2e47a6b3f5 , 这个commit 就是手动impl send+sync 然后实现 http-server 的编译通过
闭包,或者是type alias 无法用于async ,记得, 最好还是使用 trait object 或者直接是struct
the trait std::marker::Send
is not implemented for dyn futures::Future
rust 中 &self 是不可以调&mut self的 , 但是 &mut self 可以调 &self, 是一个超集
rust await的用法,await的作用是啥
Reference 是无法获取得到ownship的
rust map中获取值获得的都是引用,怎么获取得到ownship
let aaa=self.m.get(&1);
// aaa 为 &struct{}
我想活的 struct{} ,而非取地址的struct
Rust 如何clone trait object
closure 是可以直接clone的,但是如果closure 被 box 包裹 ,则不可以直接clone
如果 trait继承了clone ,并且如果实现类是closure的话,则closure 内部调用的struct 也需要实现clone才行
rc中如何 修改数据,既 rc 为mut 所修饰
vec 怎么获取得到ownship
通过remove ,或者drain
impl ExecutorContext {
pub fn next(mut self, t: &T) {
if self.executors.len() == 0 {
return;
}
let ee = self.executors.remove(0);
ee.execute(t, self);
}
}
rust 怎么 borrow reference twice
rust 如何clone vec, 并且内部元素是vector,闭包可以被clone吗
rust vec 中如果重新获取ownship
rust 使用vec+box +trait object ,vec内部的元素会有static lifetime
refcell 可以使得&self的结构体,然后可以修改数据(当然,数据得用refcell包裹)
rust 如何 trait 转为具体的struct
答: 使用any,然后 downcast_ref 即可
fn as_any(&self) -> &dyn Any;
impl CommandSelector for MockDefaultPureSelector {
fn select(&self, req: &SelectorRequest) -> Option<&'static dyn CommandTrait> {
let any = req.request.as_any();
let p;
match any.downcast_ref::() {
None => {
return None;
}
Some(v) => {
p = v;
}
}
let string_id = conv_protocol_to_string(p.protocol);
let ret = self.commands.get(&string_id).unwrap();
let a = &(**ret);
Some(a)
}
fn on_register_cmd(&mut self, cmd: &'static dyn CommandTrait) {
let id = cmd.id();
let string_id = conv_protocol_to_string(id);
self.commands.insert(string_id, cmd);
}
}
当编写dispatcher的时候,遇到一个问题, 就是 hashmap存储 trait的时候,如何定义
Option 中什么时候使用 & dyn trait object 而不是使用box ,当涉及到lifetime的时候,并且method 是个 reference
mut 和 &mut
注意,这4种是不同的用法
a: &T // immutable binding of immutable reference
mut a: &T // mutable binding of immutable reference
a: &mut T // immutable binding of mutable reference
mut a: &mut T // mutable binding of mutable reference
第一个: 参数a 不可以指向其他 reference, 并且不能修改 T 的值
第2个: 参数a 可以指向其他reference, 但是不能修改T的值
第3个: 参数a 不可以指向其他reference,但是可以修改 T内部的值
第4个: 参数a 既可以指向其他reference,又可以修改T 内部的值
Rust 当使用option的时候要注意, option+ box trait object ,当unwrap 的时候, 里面的box 是static lifetime
Raw pointer 的使用场景
对应的commit 是 e20be7650b87814fc250bcaac1d4456b2b9fda86 ,但是有个lifetime的问题,不知道怎么解决
当出现一种情况,就是使用 option
pub struct DefaultCommandSuit<'a> {
command_ctx: &'a dyn BuzzContextTrait<'a>,
concrete: Option<*mut dyn CommandSuit<'a>>,
_covariant: PhantomData<&'a ()>,
}
fn done(&mut self) -> bool {
let mut a = self.concrete.unwrap();
unsafe {
let b = a.as_mut();
let mut ccc: &mut dyn CommandSuit = b.unwrap();
ccc.done()
}
}
如果出现提示 什么不能作为trait object,试着这样改呢?(改为泛型)
not work:
pub fn as_bytes<'a>(syn: Box>) -> CellResult {
unsafe {
DEFAULT_JSON_OUTPUT_ARCHIVE.as_bytes(syn)
}
}
更改为如下 即可:
pub fn as_bytes<'a, T: Serializable<'a>>(syn: T) -> CellResult {
unsafe {
DEFAULT_JSON_OUTPUT_ARCHIVE.as_bytes(Box::new(syn))
}
}
rust result的用法
rust 如何定义 enum,并且enum 都是有默认值的
可以用这种方式:
pub enum ErrorEnums {
Kind(usize, &'static str),
}
impl ErrorEnums {
pub fn get_code(self) -> usize {
match self {
Kind(code, msg) => {
code
}
_ => {
0
}
}
}
pub fn get_msg(self) -> &'static str {
match self {
Kind(code, msg) => {
msg
}
_ => {
"wrong type"
}
}
}
}
#[derive(Debug)]
pub struct ErrorEnumsStruct {}
impl ErrorEnumsStruct {
pub const IO_ERROR: crate::cerror::ErrorEnums = crate::cerror::Kind(1, "IO FAILED");
}
Rust 如何自定义error
什么是trait object
从sync method call async method
rust 可以从 self => 调 &self ,但是不可以 &self 调 self ,就算是同一个self 也不可以
pub struct A {}
impl A {
pub fn a(self) {
println!("a")
}
}
pub struct B {
a: A,
}
impl B {
pub fn b(&self) {
println!("b");
// fail: self.a.a()
// fail:self.bb()
}
pub fn bb(&self) {
println!("bb")
}
}
macro 一直提示无法调用
解决步骤:
1. 最重要的是expand 扩展开来
2. 根据扩展开来的内容,代替原先的内容,然后进行编译,看看哪里报错了
3. macro ,注意 $crate $ 这个符号不能丢
expand 如何expand 某个文件
不可以 ,只可以直接通过mod 名称
cargo expand context(context 是context.rs 是一个模块)
rust 提示 : could not find file
in $crate
(添加自定义宏的时候)
cannot move a value of type dyn ATrait: the size of dyn ATrait cannot be statically determined
Since a reference has a fixed size
有个问题,reference 可以调用 value 的method吗
如果一个method 的 签名为self ,则 最好是return self 把所有权返回
Rust pub 函数如何指定构造类型
pub fn channel() -> (Sender, Receiver) {
}
答
let (tx, rx) = oneshot::channel::>();
真正调用之前加个类型就行
rust 如果trait的某个method 的传参为value 而不是reference,则 该trait 会触发所有权转移,所以 要么 该 trait 用 reference, 要么是 实现copy trait
rust await 只能出现在async 函数? sync 函数可以直接调用async函数吗
await 是只能出现在 async 块中 ,sync 函数可以直接调用async 函数,方法是用async block 包裹即可
async fn async_f() -> Result {
Ok(1)
}
fn sync_f() {
async {
let v = async_f().await;
match v {
Ok(value) => {
println!("{}", value)
}
Err(e) => {
println!("{}", e)
}
}
};
}
rust and_then 只能出现在async fn 中
trait Add
这种语法叫做默认类型参数
Rhs 是一个泛型类型参数(“right hand side” 的缩写),它用于定义 add 方法中的 rhs 参数。如果实现 Add trait 时不指定 Rhs 的具体类型,Rhs 的类型将是默认的 Self 类型,也就是在其上实现 Add 的类型。
rust 中trait 的这种是什么语法:
pub trait MakeServiceRef: self::sealed::Sealed<(Target, ReqBody)>
sealed::trait: 别名称为密封特质,无法被下游程序所实现的trait
self::seadled:Seadld
是为了防止 这个trait 被前天 struct 所实现,而 Seadled 是一个private trait
好处在于,如果MakeServiceRef 这个trait 变了, 但是第三方不知道, 会使得 第三方无法再使用原先的struct 去 充当这个trait
which is behind a shared reference
rust 如何从rc 中获取值
rust static/const 变量 ,当为引用的时候,是不可以为mut 的, 既 这样是错误的:, 反正就是不提倡使用全局变量
static v:&mut Configuration=&mut Configuration{}
$crate 的作用是代指 当前 crago,当前package,如果有宏,当调用本package中的其他函数的时候,可以使用这个,但是调用其他的package 就不能使用了,只能全路径
Rust ?问号的作用在于,语法糖,简化代码, 跟在 Result 后面,将error,和ok分支提前展开,然后返回( 就不需要 判断1w 个match了)
mod checked {
#[derive(Debug)]
enum MathError {
DivisionByZero,
NegativeLogarithm,
NegativeSquareRoot,
}
type MathResult = Result;
fn div(x: f64, y: f64) -> MathResult {
if y == 0.0 {
Err(MathError::DivisionByZero)
} else {
Ok(x / y)
}
}
fn sqrt(x: f64) -> MathResult {
if x < 0.0 {
Err(MathError::NegativeSquareRoot)
} else {
Ok(x.sqrt())
}
}
fn ln(x: f64) -> MathResult {
if x < 0.0 {
Err(MathError::NegativeLogarithm)
} else {
Ok(x.ln())
}
}
// 中间函数
fn op_(x: f64, y: f64) -> MathResult {
// 如果 `div` “失败” 了,那么返回 `DivisionByZero`
let ratio = div(x, y)?;
// 如果 `ln` “失败” 了,那么返回 `NegativeLogarithm`
let ln = ln(ratio)?;
sqrt(ln)
}
pub fn op(x: f64, y: f64) {
match op_(x, y) {
Err(why) => panic!("{}",match why {
MathError::NegativeLogarithm
=> "logarithm of negative number",
MathError::DivisionByZero
=> "division by zero",
MathError::NegativeSquareRoot
=> "square root of negative number",
}),
Ok(value) => println!("{}", value),
}
}
}
fn main() {
checked::op(1.0, 10.0);
}
注意注意, reference 不是所有权,不是所有权,不是所有权, &foo 调用只能说是借用,没有触发所有权转移,没有,! 并不代表获得了所有权
对象之间:要么一直 &self 调用,要么 self 一直调用, 同个对象不能 在同个签名中 &self 又self ,会出现 behind a shared reference
一旦函数签名是self ,则该函数结束之后,会被立马consumed
cannot move out of xxx
which is behind a shared reference
通常是因为 &self 调用了一个 self的方法
或者是 返回struct 内部的一个value的时候( 这时候可以用 reference 代替)
解决方法:
1. ownship 不要触发move: 都是用 self
2. 重新获取ownship: 但是这种方法只会在一些特殊的包装struct上有
3. 返回的这个值实现copy ,返回一个副本
如果struct 中只有 lifetime 'a ,但是内部的成员变量中有static ,此时会出现 : in type &'static (dyn CommandTrait<'a> + 'static)
, reference has a longer lifetime than the data it references
pub struct Command<'a>
{
pub protocol_id: ProtocolID,
pub fun: &'static Function<'a>,
pub meta_data: MetaData,
pub run_type: RunType,
}
解决方法是:
标识struct 为 static 即可
注意,如果泛型是trait的话,要么是 & dyn ,要么使用box
temporary value dropped while borrowed 这个错误通常出现在 函数式调用中, builder 这种形式 .既 返回值是个value ,然后中间某个方法的签名变成了 reference
DefaultChainExecutorBuilder::new().executor(exe22).build();
如
DefaultChainExecutorBuilder::new():
pub fn new() -> DefaultChainExecutorBuilder<'e, 'a, V> {
DefaultChainExecutorBuilder { executors: Vec::new() }
}
返回的是一个value
然后executor 函数签名:
pub fn executor(&mut self, e: &'e dyn ReactorExecutor<'e, 'a, DefaultChainExecutor<'e, 'a, V>, V>) -> &mut DefaultChainExecutorBuilder<'e, 'a, V> {
self.executors.push(e);
self
}
注意,self 是个reference, 导致 相当于有一个 let v=&mut DefaultChainExecutorBuilder::new();
然后 v 去调用executor 函数,返回V ,但是 v 如果是链式调用的话, 当v调用完executor 他就会被 drop ,因此触发了这个错误
{
let executor_v
{
let v=&mut DefaultChainExecutorBuilder::new();
executor_v=v;
}
executor_v.executor()
}
解决方法就是 定义let v 到前面:
let mut builder = DefaultChainExecutorBuilder::new();
let executor = builder.executor(exe22).build();
let mut pip = DefaultPipeline::new(executor);
pip.execute(&PipValue { name: String::from("charlie") })
rust的宗旨是,绝对的避免悬垂指针,对于struct中有引用的情况,统一都从外部传参, 而不是自己 new 出来,因为自己一旦new 出来就会触发悬空指针
pub struct DefaultPipeline<'e: 'a, 'a, V>
where
V: ExecutorValueTrait<'a>,
{
executor: &'e mut DefaultChainExecutor<'e, 'a, V>,
seald: bool,
}
executor的赋值,只能通过外部传参,或者是builder的形式
pub fn new(exe: &'e mut DefaultChainExecutor<'e, 'a, V>) -> Self {
let ret = DefaultPipeline { executor: exe, seald: true };
ret
}
rust 如果 trait+泛型+lifetime+vec 的话,建议使用 executors: &'e mut Vec<&'e dyn ReactorExecutor<'e, 'a, DefaultChainExecutor<'e, 'a, V>, V>> &dyn trait ,而非 Box 很重要的一点是,后者会是 static 的lifetime
rust 一定要记得,如果用trait bound 的话,同时又使用了 vec 等这些东西,一定要注意, 使用引用的情况下,vec 里面的box 会变成 默认的 static lifetime
pub struct BB<'e, 'a, V>
where
V: ExecutorValueTrait<'a>,
{
_marker: PhantomData<&'e ()>,
l: &'e LinkedList, V> + 'e>>,
l2: &'e Vec< Box, V> + 'e>>,
}
如,此时 l 和l2 内部的 元素都是 static lifetime 的元素
但是改成 这样就可以避免了:
pub struct BB<'e, 'a, V>
where
V: ExecutorValueTrait<'a>,
{
_marker: PhantomData<&'e ()>,
l: &'e LinkedList, V> + 'e>>,
l2: &'e Vec< Box, V> + 'e>>,
}
因为vector 我添加元素的时候,是使用 reference 添加的,导致内部的元素也会自动拥有 reference
当一个大的lifetime 试图变小的时候, 会报错, not live longger
反正记住,千万不要返回指针 reference
rust vector 用引用会有这个问题
*list1
as mutable, as it is behind a &
reference
cannot borrow data in an Rc
as mutable
rust rc 怎么取出内部的值
使用 as_ptr 指向原始指针
pub fn as_ptr(this:&Rc) -> *const T
rust 当试图 let mut 的值的时候, 右边的等值也得是mut 才行
rust 怎么mut 转为immutable
rust 反正出现错误,好好看参数,好好的看lifetime即可
Vector: cannot borrow *self
as mutable because it is also borrowed as immutable
sized 不能是supertrait
expected type parameter E
found struct
cannot be known at compilation time
this field does not implement Copy
Box
is the same as Box
,
parameter 'a
is never used
_marker: PhantomData<&'a ()>,
A value was moved whose size was not known at compile time.
提示 the trait
IChainExecutoris not implemented for
&dyn IChainExecutor``
错误代码:
impl IChainExecutor for BaseMutableChainExecutor
where
V: ExecutorValueTrait,
Self: Sized
{
fn execute(&mut self, v: V) {
if self.index < self.executors.len() {
if let Some(executor) = self.executors.get(self.index) {
// TODO,remove box new
// let vvv = &*self;
// executor.execute(v, self.as_box_executor())
}
self.index = self.index + 1
}
// TODO
println!("{:?}", v)
}
}
impl BaseMutableChainExecutor
where
V: ExecutorValueTrait,
Self: Sized
{
fn as_box_executor(&mut self) -> Box> {
Box::new(self)
}
}
在 as_box_executor 返回的是
提示live not logger
impl BaseMutableChainExecutor
where
V: ExecutorValueTrait
{
fn as_box_executor(self) -> Box> {
Box::new(self)
}
}
加上lifetime 即可
Box<&dyn trait> 是没有意义的 ,Box =&dyn trait ,不过后者得加 lifetime
rust 发现有转换问题,直接写个as 函数即可
mut self 和 &mut self 的区别
默认所有的trait都是?sized
rust 中如果 泛型只是给函数使用的, 则 struct 不需要声明 泛型
这是错误的:
pub struct DefaultChainExecutorFactory
where
CT: IListChainExecutor>, V>,
V: Debug
{}
impl ChainExecutorFactory for DefaultChainExecutorFactory
where CT: IListChainExecutor, V>
{
fn create_new_instance(&self) -> CT {
&BaseMutableChainExecutor {}
}
}
rust 不仅仅是 定义struct的时候需要指定 泛型类型 ,同时在impl 的时候也需要指定泛型类型
the trait IChainExecutor
cannot be made into an object
如何使用trait 作为泛型,或者trait +'static 是啥意思
the trait bound Box<(dyn IReactorExecutor
is not satisfied
rust: 使用了box 默认就是 实现了’static
Box is equivalent to Box
rust 如何像 go 一样,直接 type A =func(str) string 这种
使用fn 函数指针即可
type PaintF<'a> = fn(&'a str) -> ANSIGenericString<'a, str>;
注意 fn 和Fn是2个东西
fn 其实是实现了Fn, FnMut,FnOnce 的
后三者都是trait
并且,Fn,FnMut,FnOnce 这种,因为都是trait ,并且是dyn,所以使用的时候,不可以直接通过value传递,得传递指针:
type PaintF<'a> = dyn Fn(&'a str) -> ANSIGenericString<'a, str>;
let v: &PaintF = &|v| {
Red.paint(v)
};
let ret = v("asd");
println!("{}", ret);
如 let v 定义的时候,必须 加上 & 取地址符号
#cfg 的意思是平台限定 ,如#cfg(windows) 只能windows 使用如下函数
Rust 如果使用 static 全局变量的话,必须使用mutex , 但是这种情况下又会耗性能, 所以理想的情况下,可以使用threadlocal
lazy_static! {
static ref DEFAULT_LOGGER: Logger =Logger::new(Box::new(Log4rsLogger::new(&DEFAULT_MODULE)));
}
thread_local! {
static DEFAULT_LOGGER: RefCell =RefCell::new(Logger::new(Box::new(Log4rsLogger::new(&DEFAULT_MODULE))));
}
什么时候下使用 box
rust 不定长数组的定义:
pub struct CellLoggerConfiguration {
pub valid_list: [&'static str],
pub black_list: [&'static str],
}
然后赋值的时候直接:
static mut CONFIGURATION: &CellLoggerConfiguration = &CellLoggerConfiguration {
valid_list: *["rust-cell/sdk/logsdk/src/lib.rs"],
black_list: *["rust-cell/sdk/logsdk/src/lib.rs"],
};
即可 (使用* 号)
rust 切片 删除 某段区间内的数据
生命周期的源码分析
这段代码的问题在于:
fn get_log_info<'a>() -> (Option<&'a str>, Option) {
let bt= Backtrace::new();
let mut find = false;
let it = bt.frames().iter();
for f in it {
for s in f.symbols() {
match s.filename() {
None => continue,
Some(f) => {
let str = f.as_os_str().to_str().unwrap();
if !find {
for v in validList.iter() {
if !str.contains(v) {
continue;
}
find = true;
break;
}
if !find {
continue;
}
}
let lin = s.lineno().unwrap();
for v in blackList.iter() {
if str.contains(v) {
continue;
} else {
return (f.as_os_str().to_str(), s.lineno());
}
}
}
}
// println!("{:?},{:?},{:?}", s.name(), s.filename(), s.lineno())
}
}
return (None, None);
}
1. 会触发悬空指针, let bt= Backtrace::new(); 会直接当该函数结束之后,就drop
但是因为返回了frams ,而frame 又调用了iterator ,然后 最终返回的时候 是携带了对于frame的引用的
解决方法:
延长frame的生命周期,或者延长 bt的生命周期, bt从外部传参进来,不要该函数结束之后就立马drop:
fn get_log_info<'a>(bt: &'a Backtrace) -> (Option<&'a str>, Option) {
let mut find = false;
let it = bt.frames().iter();
for f in it {
for s in f.symbols() {
match s.filename() {
None => continue,
Some(f) => {
let str = f.as_os_str().to_str().unwrap();
if !find {
for v in validList.iter() {
if !str.contains(v) {
continue;
}
find = true;
break;
}
if !find {
continue;
}
}
let lin = s.lineno().unwrap();
for v in blackList.iter() {
if str.contains(v) {
continue;
} else {
return (f.as_os_str().to_str(), s.lineno());
}
}
}
}
// println!("{:?},{:?},{:?}", s.name(), s.filename(), s.lineno())
}
}
return (None, None);
}
rust 如果一个函数返回的是一个 引用, 则要注意 不能把临时变量给返回,原因在于 会 触发悬空指针
,此时 要么是返回一个value ,或者是标识static的 引用
rust 一个变量的生命周期 ,起始于刚开始定义的地方 ,结束于其依赖项的最小结束值(依赖项指的是赋值操作)
/*1*/fn main() {
/*2*/ let string1 = String::from("long string is long");
/*3*/ let result;
/*4*/ {
/*5*/ let string2 = String::from("xyz");
/*6*/ result = longest(string1.as_str(), string2./**/as_str());
/*7*/ }
/*8*/ println!("The longest string is {}", result);
/*9*/}
这段代码会编译报错,原因在于result 的生命周期起始于 第三行 ,但是 result 依赖于 string1 和string2
而string1的生命周期结束于第9行,string2 结束于 第6行,所以result的结束于第6 行,因此第8行的时候,result已经直接回收了
如果一个函数被const 修饰,则里面的逻辑调用其他method的时候,其他的method 也必须是const
usize 和其他类型的int的区别
the type [char]
cannot be indexed by i16
代码:
impl LogLevel {
pub fn get_value(self) -> i16 {
self as i16
}
}
解决方案:
将返回值修改为usize
impl LogLevel {
pub fn get_value(self) -> usize {
self as usize
}
}
字符数组的定义:
let s: [char; 5] = ['h', 'e', 'l', 'l', 'o'];
如果要解引用, 则引用的对象必须实现Copy trait 才行
rust 如果函数签名是 self ,也会将 所有权给拿走
rust 一直提示 temporary value dropped while borrowed
代码:
let r=&log::Record::builder()
.level(level)
.args(format_args!("{:}", entry.msg))
.build();
self.log4rs.log(r);
解决方案: 设置为inline 就好了
self.log4rs.log(&log::Record::builder()
.level(level)
.args(format_args!("{:}", entry.msg))
.build());
原因:
当试图定义 一个 static 变量的时候,提示: calls in statics are limited to constant functions, tuple structs and tuple variants
代码:
static m: &'static CellModule = &module::CellModule::new(1, "asd", &LogLevel::Info);
pub fn new(index: i16, name: &'static str, log_level: &'static LogLevel) -> CellModule {
CellModule { index, name, log_level }
}
解决方法:
new 函数需要有const 修饰才行
pub const fn new(index: i16, name: &'static str, log_level: &'static LogLevel) -> CellModule {
CellModule { index, name, log_level }
}
什么是借用:borrow
都是将该变量的所有权转移给该函数了,此后所有的地方都不能再使用这个函数了
生命周期:
& 取地址 代表的是借用, 可以直接使用 值,并且不会触发所有权转移
rust 中 参数为 *str 和 &str的区别
rust enum 如何获取整形值
pub enum LogLevel {
TRACE = 1,
DEBUG = 2,
INFO = 3,
WARN = 4,
ERROR = 5,
}
impl LogLevel {
pub fn is_bigger(&self, l: LogLevel) -> bool {
false
}
pub fn get_value(&self) -> i32 {
self as i32
}
}
rust match的语法为 对于case 是使用 逗号分隔的,而不是 分号
let module_id;
match module {
None => module_id = 0,
Some(v) => module_id = v.index(),
}
rust中指针要么是 *const ,要么是 *mut
*const T 和 *mut T 的区别
原来rust的变量也是可以定义 为mut的
要想直接修改成员变量的值,需要定义为mut 才行
pub struct A {
pub m: *mut HashMap,
}
这样就可以直接 a.m.inert(1,2)了
如果没有 const 或者mut 修饰的话, 会提示:
pub m: * HashMap,
| ^ expected mut or const in raw pointer type
|
= help: use `*mut T` or `*const T` as appropriate
*const的区别在于
rust 如果要从self 中 的成员变量返回 mut 类型,则 self 需要定义为 mut self
pub fn get_log_receivers(&mut self, m: &dyn ModuleTrait, l: LogLevel, log_type: i64) -> HashSet> {
let cache = self.thread_local.get_or(|| LogThreadCache::new());
let version = self.version.get_mut();
}
如 self 就定义为了 &mut, 这样version 才可以 get_mut
rust hashMap 提示 类型不匹配
用法有问题:
impl LogThreadCache {
pub fn new() -> &Self {
LogThreadCache { log_receiver_set_cache_by_mask: HashMap::new(), log_receiver_set_cache_by_key: () }
}
}
应该这样用:
&LogThreadCache {
log_receiver_set_cache_by_mask: HashMap::>::new(),
log_receiver_set_cache_by_key: HashMap::>::new(),
}
rust如何查看编译展开后的代码
move 关键字: 可以使得多线程拿到所有权
use std::thread;
fn main() {
let v = vec![1, 2, 3];
// 如果没有move, 拿到v 的所有权会报错,有就不会报错
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
handle.join().unwrap();
// 下面代码会报错borrow of moved value: `v`
// println!("{:?}",v);
}
这是什么写法:
struct impl的时候,直接使用macro
pub struct thread_local_demo {}
impl thread_local_demo {
thread_local! {
}
}
move 是什么意思,及其作用
rust 如何定义一个全局变量
rc
rc 简单总结
Rc/Arc
是不可变引用,你无法修改它指向的值,只能进行读取,如果要修改,需要配合后面章节的内部可变性 RefCell
或互斥锁 Mutex
Rc
只能用于同一线程内部,想要用于线程之间的对象共享,你需要使用 Arc
Rc
是一个智能指针,实现了 Deref
特征,因此你无需先解开 Rc
指针,再使用里面的 T
,而是可以直接使用 T
,例如上例中的 gadget1.owner.name
但是rc 都是包装的不可变借用
希望在堆上分配一个对象供程序的多个部分使用且无法确定哪个部分最后一个结束时,就可以使用 Rc
成为数据值的所有者
fn main() {
let s = String::from("hello, world");
// s在这里被转移给a
let a = Box::new(s);
// 报错!此处继续尝试将 s 转移给 b
let b = Box::new(s);
}
使用rc
use std::rc::Rc;
fn main() {
let a = Rc::new(String::from("hello, world"));
let b = Rc::clone(&a);
assert_eq!(2, Rc::strong_count(&a));
assert_eq!(Rc::strong_count(&a), Rc::strong_count(&b))
}
Box
将动态数据固定化的秘诀就是使用引用指向这些动态数据,然后在引用中存储相关的内存位置、长度等信息。
只能通过引用或 Box
的方式来使用特征对象
Rust 中常见的 DST
类型有: str
、[T]
、dyn Trait
,它们都无法单独被使用,必须要通过引用或者 Box
来间接使用 。
#![allow(unused)]
fn main() {
fn foobar_1(thing: &dyn MyThing) {} // OK
fn foobar_2(thing: Box) {} // OK
fn foobar_3(thing: MyThing) {} // ERROR!
}
实际上,一个闭包并不仅仅实现某一种 Fn
特征,规则如下:
FnOnce
特征,因此任何一个闭包都至少可以被调用一次FnMut
特征Fn
特征闭包也是有 可变闭包和不可变闭包的
借用的规则:要么多个不可变借用,要么一个可变借用
生命周期只有 'a:'b 的时候, a的生命周期的值才能 返回 约束为 'b 的返回值
T:'a
生命周期 'static
意味着能和程序活得一样久,例如字符串字面量和特征对象
T: 'static
,有时候它会给你奇迹如果参数中一个生命周期是’a,一个是’b 的时候,怎么处理
使用生命周期约束语法
impl<'a: 'b, 'b> ImportantExcerpt<'a> {
fn announce_and_return_part(&'a self, announcement: &'b str) -> &'b str {
println!("Attention please: {}", announcement);
self.part
}
'a:'b : 生命周期约束语法,表明 a 肯定活的比b要久
或者是通过where 也是可以的
impl<'a> ImportantExcerpt<'a> {
fn announce_and_return_part<'b>(&'a self, announcement: &'b str) -> &'b str
where
'a: 'b,
{
println!("Attention please: {}", announcement);
self.part
}
}
什么时候需要显示的标注生命周期, 当参数不同的时候
结构体中申明生命周期,代表的是,希望该变量活的比结构体要久
struct ImportantExcerpt<'a> {
part: &'a str,
}
part 希望要比ImportantExcerpt 活的更久
#[derive(Debug)]
struct ImportantExcerpt<'a> {
part: &'a str,
}
fn main() {
let i;
{
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().expect("Could not find a '.'");
i = ImportantExcerpt {
part: first_sentence,
};
}
println!("{:?}",i);
}
这是错误的, ImportantExcerpt 比novel 活的久了,因此无法编译通过
指针会有悬垂指针问题,以及生命周期问题, 非指针有所有权问题
悬垂指针的解决方案
生命周期标注并不会改变任何引用的实际作用域,标记的生命周期只是为了取悦编译器,让编译器不要难为我们
在存在多个引用时,编译器有时会无法自动推导生命周期,此时就需要我们手动去标注,通过为参数标注合适的生命周期来帮助编译器进行借用检查的分析。
生命周期主要是为了防止悬垂指针
悬垂指针: 指的是 当变量离开作用域之后,就会被内存回收, 但是又被当做 结果值返回了
#![allow(unused)]
fn main() {
fn dangle() -> &String { // dangle 返回一个字符串的引用
let s = String::from("hello"); // s 是一个新字符串
&s // 返回字符串 s 的引用
} // 这里 s 离开作用域并被丢弃。其内存被释放。
// 危险!
let aaaa=dangle() // 这里就会触发悬垂指针了 ,因为dangle 的返回值调用完毕之后就已经被回收了
}
可变借用和借用可变是不同的
let mut a= String::from("asd");
let s1= &a; // 不可变借用
let s2=&mut a; // 可变借用
可变引用与不可变引用是不可以同时存在的
let mut a= String::from("asd");
let s1 = &a; // 不可变引用
let s2= &a; // 不可变引用
let s3=&mut a; // 可变引用
因为a 已经被s1,s2 借用为了不可变了
获取变量的引用,称之为借用
& 符号即是引用,允许使用值,但是不获取所有权
注意,如果单纯的只是借用 ,是无法修改值的
fn main() {
let s = String::from("hello");
change(&s);
}
fn change(some_string: &String) {
some_string.push_str(", world");
}
change 是无法修改值的
这时候只能使用可变引用,可变引用是可以修改值的,但是可变引用在同一作用域只可以有一个
#![allow(unused)]
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
}
错误的写法, r1,r2 2个可变的引用了
rust对于 栈上的数据是可以直接 所有权转移的
let a=5;
let b=a;
这一段是不会报错的
这是浅拷贝,性能非常高
适用的类型为:
u32
。bool
,它的值是 true
和 false
。f64
。char
。Copy
的时候。比如,(i32, i32)
是 Copy
的,但 (i32, String)
就不是。&T
,例如转移所有权中的最后一个例子,但是注意: 可变引用 &mut T
是不可以 Copy的rust 如何解指针
rust提示 used of a moved value
原因是因为
1. 定义了一个 值对象
2. 参数入参的时候也是值对象,当参数为值对象的时候,编译器会判断是否实现了Copy这个函数,如果是,则会发生一次memcopy,并且后面也可以继续使用这个值对象,如果没有实现,则当第二次使用的时候就会报这个错误(所有权转移)
解决方法:
大多时候,function 并不需要参数的所有权,这时候则引出 `借`的概念, 通过传递指针即可
rust 返回值该怎么定义好
泛型接口的正确写法
impl IConsumer for DefaultLogConsumer
{
fn consume(&self,event: T) -> V {
}
}
这样就可以当consume的时候可以获得代码提示了
提示cant move
rust中函数变量有个self的作用
rust中切片的定义
是通过vec
pub struct DefaultLogConsumer
{
hooks: Vec>,
}
rust 中只有trait 是有继承的,struct没有继承
#[derive(Debug, Clone, PartialEq)]
接口之间继承
mod 管理
rust的泛型如何指定类型
通过where
pub trait IEventConsumer: IConsumer
where
T: IEvent,
V: IEventResult
{}
pub trait ILogConsumer: IEventConsumer {
fn log_able(l: LogLevel) -> bool;
}
rust 的泛型如何编写
pub trait IConsumer {
fn consume(T) -> V;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QwXbqTii-1656553730691)(/Users/lvcong/Library/Application Support/typora-user-images/image-20220331062334904.png)]
提示: use of moved value
rust的接口如何继承
pub trait ModuleTrait: Display {
fn index(&self) -> u16;
fn name(&self) -> String;
}
rust 当 trait 作为参数的时候会遇到问题,就是运行会提示 cannot be made into an object
rust的编写规则:
rust 如何引用同一个根目录下,不同的mod
https://wiki.jikexueyuan.com/project/rust-primer/module/module.html 讲的挺好
层级结构为:
-a
-b
-c
-aa
-bb
-cc
c中如何引用cc:
通过super:
dyn 关键字
与trait 一起分配使用,强调相关trait方法是动态调用的, 为什么有这个关键字呢,因为rust 在分配的时候都是已知内存的,无法动态分配,如果不用这个的话,相同接口就不能以不同的实现传参或者返回 , dyn 通常与Box 一起使用
struct Sheep {}
struct Cow {}
trait Animal {
// 实例方法签名
fn noise(&self) -> &'static str;
}
// 实现 `Sheep` 的 `Animal` trait。
impl Animal for Sheep {
fn noise(&self) -> &'static str {
"baaaaah!"
}
}
// 实现 `Cow` 的 `Animal` trait。
impl Animal for Cow {
fn noise(&self) -> &'static str {
"moooooo!"
}
}
// 返回一些实现 Animal 的结构体,但是在编译时我们不知道哪个结构体。
fn random_animal(random_number: f64) -> Box {
if random_number < 0.5 {
Box::new(Sheep {})
} else {
Box::new(Cow {})
}
}
fn main() {
let random_number = 0.234;
let animal = random_animal(random_number);
println!("You've randomly chosen an animal, and it says {}", animal.noise());
}
'a的 作用
'a is a lifetime notation named a,
代表的是一个a 这个对象的生命周期
a可以是任意类型
&i32 // 常规引用
&'a i32 // 含有生命周期注释的引用
&'a mut i32 // 可变型含有生命周期注释的引用
&'static str 什么意思
& 代表的是 获取值的引用
'static : 使得该变量可以拥有 static的生命周期
str 就是具体的类型了
这句话的意思是,使得 这个 引用具有 static的生命周期
As a conclusion, &'static str is a reference to the UTF-8 encoded variable length of byte sequence, which is valid for the entire lifetime of the process. But how can we obtain such type? Normally it's from the string literals, which are embeded directly on the executable binary(like .rodata section of the elf file) and loaded to the read-only section of the memory by the OS before execution.
rust中的String 和str的区别
String
类型,而如果是作为一个不会更改的常量存在,则应该使用 str
类型进行操作Rust 中有类似于Java的Object ,或者是go中的interface 这种万能类型的吗
rust mod 好像一个mod 只能只有一个文件
不是的, rust的模块化, 当 在目录下创建之后, 必须在main.rs 中声明使用才行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XsfT1PxC-1656553730692)(/Users/lvcong/Desktop/personal/documents/nodes/个人/计划/个人框架/imgs/rust01-模块化.jpg)]
我在logsdk 下创建了一个文件夹,叫做logger ,因为是单独定义为一个单独的包,所以还需要添加mod.rs ,mod.rs内的内容为:
pub mod logger;
mod common;
因为我的主文件是 logger.rs ,所以会有一个pub mod logger ,然后因为还有另外一个文件,所以又会有另外一个 mod common ,有点奇怪哈
然后最重要的一步是: 需要在main.rs 中 声明 ,mod logger,才会起作用
rust 接口如何定义
extern crate 的作用
rust的静态方法和实例方法区分是通过 ,参数中是否携带self
// 实现的代码块,`Point` 的所有方法都在这里给出
impl Point {
// 这是一个静态方法(static method)
// 静态方法不需要被实例调用
// 这类方法一般用作构造器(constructor)
fn origin() -> Point {
Point { x: 0.0, y: 0.0 }
}
// 这是一个实例方法(instance method)
// `&self` 是 `self: &Self` 的语法糖(sugar),其中 `Self` 是方法调用者的
// 类型。在这个例子中 `Self` = `Rectangle`
fn area(&self) -> f64 {
// `self` 通过点运算符来访问结构体字段
let Point { x: x1, y: y1 } = self.p1;
let Point { x: x2, y: y2 } = self.p2;
// `abs` 是一个 `f64` 类型的方法,返回调用者的绝对值
((x1 - x2) * (y1 - y2)).abs()
}
}
宏
宏是如何进行模式匹配的
macro_rules! hey{
() => {}
}
() => {}看起来很神秘,因为它不是标准的rust语法,是macro_rules!这个宏自己发明的,用来表示一条宏规则,=>左边是匹配模式,右边是等待展开的代码:
trait 的作用
rust 中 # 的作用
rust 如何创建多模块: rust file is not included in module tree,no cargo projects found
rust 如何创建package ,类似于Java 的go.mod 或者是 新的工程
通过 cargo new
cargo new demo