Talk Is Cheap,Show Me The Code. Rust


  • 看了文档 : 1天
  • 直接写框架
  • 学习tokio 异步编程
  • 技术选型
    • 技术选型,主要是选择市面上主流的框架,看他们的源码是怎么玩的, web 选择的是rocket ,rocket内部的选型是tokio +hyper 所以,我的框架也会是根据tokio+hyper 然后,先看tokio 是怎么用的, 然后再看hyper 怎么嵌入, hyper 是bind tcpListener, 然后围绕tcpListener通过future 封装 request & response , 那跟我之前的框架倒也差不多,唯一的区别的是tcpListener rust 因为borrow 有点麻烦~
    • log 选用的和Java 类似,采用 log4rs 作为基础库

记录

  • 2022-06-30

    • rust 是唯一一门,让我对于一些细碎的东西也忍不住写ut的语言~ (根本原因的话那肯定是不够熟练)
  • 2022-06-24

    • 现在卡在di 这,如何便携的生成
  • 2022-06-18

    • 初见雏形
  • 2022-06-15

    • Rust 是精简设计,精简抽象,但是也抑制了拓展(虽然抽象太多会是魔鬼)
  • 2022-06-13

    • rust 就是精简我的设计,之前写go和java 框架的时候,有几个点的确是模棱两可的,然后到了rust 发现会走不通,只能直接删除…
  • 2022-05-24

    • 好吧,以前框架的写法,在rust很多会走不通, 抽象抽太多层感觉有点麻烦
    • 写框架是一个取长补短的过程(但是初版不会,初版更多是借鉴,借鉴别人rust怎么玩的),又看了一个新语言的框架源码, 看的源码 越来越多了!! 但是 最推崇的还是Spring ! ,没有之一
  • 2022-05-20

    • 记录下rust 吧,学了快一个月了,写个rust框架
  • 2022-05-23

    • 第三次重构ing

自学

  • 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 怎么判断类型

    • 使用any 然后做下转判断
  • rust channel 如何close

    • 通过drop (drop 相当于)
  • rust 如何监听ctrl+c 退出

    • 通过ctrlc 库 可以
    • 或者是tokio 库,但是这种方案未尝试
  • trait 如何添加lifetime

    • 跟正常的一样,直接method 添加即可
  • refcell 调用borrow的时候提示: type annotations needed for &Borrowed

    • 未知~,后面再遇到的时候记得补一下
  • 如果trait 用self 作为参数的话,会出现 cant know size compile time ,

    • 解决方法
      • self => & reference
      • 或者是 self:Box 等
  • 如果外层的 self 是个brorrow 的时候, 但是内层的 一个 成员变量的method 为 self,需要ownship的时候, 这个成员变量,可以用refcell来包裹

    • 具体的commit: fbb45b9db8b8d6191fdfb7fae0edf5d287b54c06

    • pub struct HttpExtension {
          server: Arc<RefCell<HttpServer>>,
      }
      
      impl NodeExtension for HttpExtension {
          fn module(&self) -> CellModule {
              HttpModule
          }
          fn on_start(&mut self, ctx: Arc<NodeContext>) -> CellResult<()> {
              let s = self.server.take(); // 注意这一行, 直接take 可以获得 ownship
              ctx.tokio_runtime.spawn(s.start());
              Ok(())
          }
      }
      其实内部就是 mem:replace , 使用的是 server 的default 函数 ,所以一旦使用了,就再也不能使用了,因为是一个default 对象了
      
  • refcell 和cell的区别

    • RefCellCell 的区别在于,Cell只能用于那么实现了CopyTrait的类型,其余的类型使用RefCellRefCell让程序在修改变量时必须先获得一个写锁。
  • shaku 同个类型依赖多个vec

  • rust 宏如何输入string ,既 参数为string 的时候,宏调用的也是string

    • stringfy 通过这个来转成string
  • rust .except 的用法

    • 就是panic的时候的msg
  • rust channel 如何send error

    • no way
  • rust 一单某个struct 出现了 lifetime,则这个lifetime 很可能会贯穿整个程序(所有相关的代码都会有), 😃 参考这个commit:

    • f2348126751b4a24a516e408ae08717b0b58e5f0
  • rust box trait 可以修改值吗

    • 可以,要记得 ,rc & arc 不可以
  • Rust 当从sync 转为async的时候, 整个过程涉及到的所有的rc 都需要更改为arc ,同时 如果涉及到trait 的时候, async-trait 这个库自身编译时又有限制,返回的future 必须+ Send ,所以这里会有一个问题是,如果整个流程中某个struct 没有实现 send 的话, 则 编译的时候就会过不了,提示: the trait std::marker::Send is not implemented for dyn futures::Future<Output = ()>

    • 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<Output = ()>

  • 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

    • 这时候可以使用 rc/arc (当然,此时的clone并不是真的clone closure,而只是share reference 而已)
    • https://users.rust-lang.org/t/how-to-clone-a-boxed-closure/31035/10
  • 如果 trait继承了clone ,并且如果实现类是closure的话,则closure 内部调用的struct 也需要实现clone才行

  • rc中如何 修改数据,既 rc 为mut 所修饰

    • 不可以,只能使用refcell 或者是cell
  • vec 怎么获取得到ownship

    • 通过remove ,或者drain

      •  impl<T> ExecutorContext<T> {
                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

    • noway 除非,vec 里面的是RefCell
  • 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::<MockRequest>() {
                  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的时候,如何定义

    • 也是一样的,定义box 或者使用取地址
  • 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 <box / & > 然后无法 defer 的时候, 可以使用raw pointer 来defer

      • 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<dyn Serializable<'a>>) -> CellResult<Bytes> {
          unsafe {
              DEFAULT_JSON_OUTPUT_ARCHIVE.as_bytes(syn)
          }
      }
      更改为如下 即可:
      
      pub fn as_bytes<'a, T: Serializable<'a>>(syn: T) -> CellResult<Bytes> {
          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

    • 指向trait的指针,如A 是trait 则 &A ,或者 Box 都是 trait object
  • 从sync method call async method

    • 使用 framework即可
  • 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

    • 通常出现这个问题都是因为, 这个trait的函数签名是 value 而不是reference, 如果是reference,则Since a reference has a fixed size
  • 有个问题,reference 可以调用 value 的method吗

    • 可以是可以,但是得copy
  • 如果一个method 的 签名为self ,则 最好是return self 把所有权返回

  • Rust pub 函数如何指定构造类型

    • pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
      }
      
      • let (tx, rx) = oneshot::channel::<Response<Body>>();
        真正调用之前加个类型就行
        
  • 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<usize, Error> {
                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=Self> {

    • 这种语法叫做默认类型参数

    • Rhs 是一个泛型类型参数(“right hand side” 的缩写),它用于定义 add 方法中的 rhs 参数。如果实现 Add trait 时不指定 Rhs 的具体类型,Rhs 的类型将是默认的 Self 类型,也就是在其上实现 Add 的类型。
      
  • rust 中trait 的这种是什么语法:

    • pub trait MakeServiceRef<Target, ReqBody>: 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<f64, MathError>;
      
          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<Box<dyn ReactorExecutor<'e, 'a, DefaultChainExecutor<'e, 'a, V>, V> + 'e>>,
              l2: &'e Vec< Box<dyn ReactorExecutor<'e, 'a, DefaultChainExecutor<'e, 'a, V>, V> + 'e>>,
          }
          如,此时 l 和l2 内部的 元素都是 static lifetime 的元素 
          但是改成 这样就可以避免了:
          pub struct BB<'e, 'a, V>
              where
                  V: ExecutorValueTrait<'a>,
          {
              _marker: PhantomData<&'e ()>,
              l: &'e LinkedList<Box<dyn ReactorExecutor<'e, 'a, DefaultChainExecutor<'e, 'a, V>, V> + 'e>>,
              l2: &'e Vec< Box<dyn ReactorExecutor<'e, 'a, DefaultChainExecutor<'e, 'a, V>, V> + 'e>>,
          }
      因为vector 我添加元素的时候,是使用 reference 添加的,导致内部的元素也会自动拥有 reference
      
  • 当一个大的lifetime 试图变小的时候, 会报错, not live longger

  • 反正记住,千万不要返回指针 reference

  • rust vector 用引用会有这个问题

    • cannot borrow *list1 as mutable, as it is behind a & reference
      • 解决方法:

  • cannot borrow data in an Rc as mutable

    • Rc 都是 immutable ,都是只适用于可读的环境(read only)
  • rust rc 怎么取出内部的值

    • 使用 as_ptr 指向原始指针

      • pub fn as_ptr(this:&Rc<T>) -> *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

    • https://stackoverflow.com/questions/31060851/generics-error-expected-type-parameter-found-struct
  • cannot be known at compilation time

  • this field does not implement Copy

    • 一种解决方法是,将struct中的 value更改为reference
  • Box<dyn Foo> is the same as Box<dyn Foo + 'static>,

  • parameter 'a is never used

    • _marker: PhantomData<&'a ()>,
      
  • A value was moved whose size was not known at compile time.

    • 这是因为 函数 receiver 是个value导致
  • 提示 the trait IChainExecutoris not implemented for&dyn IChainExecutor``

    • 错误代码:
       
       impl<V> IChainExecutor<V> for BaseMutableChainExecutor<V>
          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<V> BaseMutableChainExecutor<V>
          where
              V: ExecutorValueTrait,
              Self: Sized
      {
          fn as_box_executor(&mut self) -> Box<dyn IChainExecutor<V>> {
              Box::new(self)
          }
      }
      在 as_box_executor 返回的是
      
  • 提示live not logger

    • impl<V> BaseMutableChainExecutor<V>
          where
              V: ExecutorValueTrait
      {
          fn as_box_executor(self) -> Box<dyn IChainExecutor<V>> {
              Box::new(self)
          }
      }
      加上lifetime 即可
      
  • Box<&dyn trait> 是没有意义的 ,Box =&dyn trait ,不过后者得加 lifetime

  • rust 发现有转换问题,直接写个as 函数即可

  • mut self 和 &mut self 的区别

    • 区别在于 前者 当调用完func ,所有权被转移到了func 中, func 调用结束就不可以再调用了,除非返回self
  • 默认所有的trait都是?sized

  • rust 中如果 泛型只是给函数使用的, 则 struct 不需要声明 泛型

    • 这是错误的:
      pub struct DefaultChainExecutorFactory<CT, V>
          where
              CT: IListChainExecutor<Box<dyn IReactorExecutor<V>>, V>,
              V: Debug
      
      {}
      
      impl<CT, V> ChainExecutorFactory<CT, V> for DefaultChainExecutorFactory<CT, V>
          where CT: IListChainExecutor<dyn IReactorExecutor<V>, 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<V> + 'static)>: IReactorExecutor<V> is not satisfied

  • rust: 使用了box 默认就是 实现了’static

    • Box<dyn Trait> is equivalent to Box<dyn Trait + 'static
      
  • 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<Logger> =RefCell::new(Logger::new(Box::new(Log4rsLogger::new(&DEFAULT_MODULE))));
      }
      
      
  • 什么时候下使用 box

    • 当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候
    • 当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候
    • 当希望拥有一个值并只关心它的类型是否实现了特定 trait 而不是其具体类型的时候
  • 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<u32>) {
      		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<u32>) {
          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的区别

    • usize 操作系统敏感,如果操作系统是64位的,则返回的是64的byte的值
  • 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 引用,只可以引用生命周期 比 当前let 大的值
  • & 取地址 代表的是借用, 可以直接使用 值,并且不会触发所有权转移

  • rust 中 参数为 *str 和 &str的区别

    • 其实 &str 就是 *str,但是 *str 还有 *const str,和 *mut str,对应的是 &str 和 &mut str, 如果 *str 作为参数,还需要指明是 *const 还是 mut
  • 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, 不可更改内部的值
  • *const T 和 *mut T 的区别

    • 解引用之后, *const T 对应的是 &T ,而 *mut T 对应的是&mut T
  • 原来rust的变量也是可以定义 为mut的

    • 要想直接修改成员变量的值,需要定义为mut 才行
      pub struct A {
          pub m: *mut HashMap<i32, i32>,
      }
      这样就可以直接 a.m.inert(1,2)了
      如果没有 const 或者mut 修饰的话, 会提示:
          pub m: * HashMap<i32, i32>,
          |            ^ 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<ILogEventConsumer<ILogEvent, IEventResult>> {
              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::<i64, dyn ILogEventConsumer<dyn ILogEvent, dyn IEventResult>>::new(),
                  log_receiver_set_cache_by_key: HashMap::<i64, dyn ILogEventConsumer<dyn ILogEvent, dyn IEventResult>>::new(),
              }
      
  • rust如何查看编译展开后的代码

    • cargo expand
  • 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 如何定义一个全局变量

    • 用static
  • rc

    • rc 简单总结

      • Rc/Arc 是不可变引用,你无法修改它指向的值,只能进行读取,如果要修改,需要配合后面章节的内部可变性 RefCell 或互斥锁 Mutex
      • 一旦最后一个拥有者消失,则资源会自动被回收,这个生命周期是在编译期就确定下来的
      • Rc 只能用于同一线程内部,想要用于线程之间的对象共享,你需要使用 Arc
      • Rc<T> 是一个智能指针,实现了 Deref 特征,因此你无需先解开 Rc 指针,再使用里面的 T,而是可以直接使用 T,例如上例中的 gadget1.owner.name
    • 但是rc 都是包装的不可变借用

    • 希望在堆上分配一个对象供程序的多个部分使用且无法确定哪个部分最后一个结束时,就可以使用 Rc 成为数据值的所有者

      • 既rc 可以使得一个值同一时刻拥有多个所有者 (通常情况下会触发所有权转移问题, 但是通过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<dyn MyThing>) {} // OK
      fn foobar_3(thing: MyThing) {}          // ERROR!
      }
      
      
  • 实际上,一个闭包并不仅仅实现某一种 Fn 特征,规则如下:

    • 所有的闭包都自动实现了 FnOnce 特征,因此任何一个闭包都至少可以被调用一次
    • 没有移出所捕获变量的所有权的闭包自动实现了 FnMut 特征
    • 不需要对捕获变量进行改变的闭包自动实现了 Fn 特征
  • 闭包也是有 可变闭包和不可变闭包的

  • 借用的规则:要么多个不可变借用,要么一个可变借用

  • 生命周期只有 'a:'b 的时候, a的生命周期的值才能 返回 约束为 'b 的返回值

  • T:'a

    • 表示类型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,它的值是 truefalse
      • 所有浮点数类型,比如 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 返回值该怎么定义好

    • 好像不是使用result 就是使用option
  • 泛型接口的正确写法

    •  impl<T:ILogEvent,V:IEventResult> IConsumer<T,V> for DefaultLogConsumer
          {
              fn consume(&self,event: T) -> V {
              }
          }
          这样就可以当consume的时候可以获得代码提示了
      
  • 提示cant move

    • rust的所有权问题, 这个问题暂时无法回答
  • rust中函数变量有个self的作用

    • 类似于this
  • rust中切片的定义

    • 是通过vec

      • pub struct DefaultLogConsumer
            {
                hooks: Vec<dyn ILogHook<LogEntry>>,
            }
        
  • rust 中只有trait 是有继承的,struct没有继承

  • #[derive(Debug, Clone, PartialEq)]

    • 这种代表的是这个struct 自动有这些函数
  • 接口之间继承

  • mod 管理

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SNbaVH9D-1656553730690)(/Users/lvcong/Library/Application Support/typora-user-images/image-20220331064123454.png)]
    • 对于这种executor 内部又有多个子模块, 这时候外部的模块 ,dependencies 中要全都有这些模块才可以
  • rust的泛型如何指定类型

    • 通过where

      • pub trait IEventConsumer<T, V>: IConsumer<T, V>
        where
        	T: IEvent,
        	V: IEventResult
        {}
        
        pub trait ILogConsumer<T, V>: IEventConsumer<T, V> {
        	fn log_able(l: LogLevel) -> bool;
         }
        
  • rust 的泛型如何编写

    • pub trait IConsumer<T, V> {
          fn consume(T) -> V;
      }
      
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QwXbqTii-1656553730691)(/Users/lvcong/Library/Application Support/typora-user-images/image-20220331062334904.png)]

    • 这种情况下怎么在lib.rs 中引用consumer.rs
      • 通过创建mod.rs 文件即可
        • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HHYGbUcl-1656553730692)(./imgs/mod.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

    • 需要使用box 作为参数
  • rust的编写规则:

    • 通常情况下一个module 里面只有一个mod 的话,则只有一个lib.rs 即可,但是如果有多个文件的话,可以创建一个mod.rs 专门写有哪些文件mod
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-slFAKMjC-1656553730692)(/Users/lvcong/Desktop/personal/documents/nodes/个人/计划/个人框架/imgs/1.jpg)]
  • 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<dyn Animal> {
            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 这种万能类型的吗

    • 没有, 所以我如果 Log ,要 类似于Java ,go 那样的话,只能够修改为接口类型才行
  • 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 接口如何定义

    • 通过trait
  • 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

    • 确切的说,如何在clion 中创建多个rust 工程,
      • A: 通过关键字: workspace, 最外层是workspace 目录,然后添加member 即可
        • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IIJVTjDr-1656553730692)(/Users/lvcong/Desktop/personal/documents/nodes/个人/计划/个人框架/imgs/rust如何创建多个模块.jpg)]
  • rust 如何创建package ,类似于Java 的go.mod 或者是 新的工程

    • 通过 cargo new

      • cargo new demo
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值