< 返回版块

zjhken 发表于 2022-12-24 14:05

Tags:lifetime,static

最近在写一点东西, 但是遇到好多生命周期的大问题. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ef6a8541d4dbe806e6f3b7d61f519180

App的start方法入参必须是&'static mut self, 因为下面的调用需要用到App的f属性, f是一个异步方法. 但是在执行start时却报App生命周期不够. 作为作者, 我是知道app这个变量是不会drop的因为start是一个blocking function. 但是编译器不知道, 那应该怎么告诉它呢?

试过将app放到static, 但是static不能是mut, 所以失败了.

====== 2022-12-25 根据大家的建议, 更新了代码, 还是有问题解决不了 ============== 将&mut self 改为 mut self App的field是vector

use core::future::Future;
use futures::future::{BoxFuture, FutureExt};

struct App {
    v: Vec<fn(&mut u8) -> BoxFuture<'_, u8>>
}

impl App {
    fn new() -> App {
        return App {
            v: vec![]
        }
    }
    fn start(mut self) -> Result<(), std::io::Error> {
        let v = self.v;
        loop {
            let n2 = 3u8; // n2必须在此出现, 实际上每次都是新的值
            tokio::spawn(async move{
                let mut n = 9u8 + n2; // n必须用到n2的值
                for f in v {
                    f(&mut n).await;
                    println!("n = {}", n);
                }
            });
        }

        Ok(())
    }
    
    fn set_func(&mut self, f: fn(&mut u8) -> BoxFuture<'_, u8>) -> &mut App {
        self.v.push(f);
        return self;
    }
}

async fn haha(ctx: &mut u8) -> u8 {
    dbg!(*ctx);
    *ctx = 20;
    *ctx
}


#[tokio::main]
async fn main() {
    let mut app = App::new();
    app.set_func(|ctx| async move { haha(ctx).await }.boxed());
    app.start().unwrap();
}



Ext Link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ef6a8541d4dbe806e6f3b7d61f519180

评论区

写评论
作者 zjhken 2022-12-27 20:21

感谢! 我试着这么改. 解决了.

loop {
    let v = self.v.clone();
    tokio::spawn(async move {
       let v = &v.clone();
       // another 闭包 here
    }
)

}

--
👇
苦瓜小仔: &'static self 和 &'static mut self 是相当无用的。

你需要掌握所有权

loop {
    let v = self.v.clone();
    // rest
}
作者 zjhken 2022-12-27 20:15

有考虑过, 但是在这里使用在API的角度上有点怪怪的

--
👇
closetool: 有考虑过lazy_static吗 https://colobu.com/2019/09/08/rust-lib-per-week-lazy-static/

closetool 2022-12-26 10:14

有考虑过lazy_static吗 https://colobu.com/2019/09/08/rust-lib-per-week-lazy-static/

wangbyby 2022-12-25 23:52
  1. 如果你不在spawn中改变APP的话,Arc是一个好选择 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dbef0123522d309843ce27da111d20c9
  2. 如果你在spawn中改变APP,那么Arc+Mutex是一个可行解

--
👇
zjhken: Good Idea! 我更新了代码

--
👇
snylonue: 直接改成 mut self 怎么样

苦瓜小仔 2022-12-25 23:45

&'static self 和 &'static mut self 是相当无用的。

你需要掌握所有权

loop {
    let v = self.v.clone();
    // rest
}
作者 zjhken 2022-12-25 22:34

Good Idea! 我更新了代码

--
👇
snylonue: 直接改成 mut self 怎么样

作者 zjhken 2022-12-25 22:26

感谢解答. 我更新了代码, 之前的简化太多了. 这次, 在App中的实质上是vec, 而且被编译器要求要在start函数加'statc.

👇
苦瓜小仔: 函数指针类型实现了 Copy trait

所以,直接传函数指针就行:

苦瓜小仔 2022-12-25 19:21

函数指针类型实现了 Copy trait

所以,直接传函数指针就行:

fn start(&self) -> Result<(), std::io::Error> {
    let f = self.f;
    tokio::spawn(async move {
        let mut n = 9u8;
        f(&mut n).await;
    });
    Ok(())
}

playground

snylonue 2022-12-25 12:41

直接改成 mut self 怎么样

苦瓜小仔 2022-12-25 12:26

你需要 Arc 而不是 &'static mut

playground

作者 zjhken 2022-12-25 10:31

有试过, 但是这样必须unsafe, 所以很纠结

👇
Neutron3529: 为什么不干脆把app定义成static变量呢?

Neutron3529 2022-12-24 21:54

为什么不干脆把app定义成static变量呢?

static mut app:App = App {
    f: |ctx| async move { haha(ctx).await }.boxed(),
};
#[tokio::main]
async fn main() ->!{
    unsafe{app.start()};
}
wangbyby 2022-12-24 15:00

简单粗暴的绕过下

let a = self.f;
        tokio::spawn(async move{
            let mut n = 9u8;
            a(&mut n).await;
            println!("n = {}", n);
        });

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=bd30e576c5127489a4ec8048c6b9af47

1 共 13 条评论, 1 页