< 返回版块

rascalrr 发表于 2023-11-09 14:08

Tags:泛型,生命周期

trait CodecIF: Send + Sync {
    fn new() -> Self;
    fn process(&self);
}

struct Channel<T> {
    pub id: usize,
    pub tx: UnboundedSender<Msg>,
    _codec: std::marker::PhantomData<T>,
}

impl<T: CodecIF> Channel<T> {
    pub fn new(id: usize, map: Arc<DashMap<usize, Channel<T>>>) -> Self {
        let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<Msg>();
        tokio::spawn(async move {
            let mut codec = T::new();

            codec.process();

            map.remove(&id);
        });

        Channel {
            id,
            tx,
            _codec: std::marker::PhantomData::default(),
        }
    }
}

编译错误:

error[E0310]: the parameter type `T` may not live long enough
  --> src\channel.rs:65:9
   |
65 | /         tokio::spawn(async move {
66 | |             let mut codec = T::new();
67 | |
68 | |             codec.process();
69 | |
70 | |             map.remove(&id);
71 | |         });
   | |__________^ ...so that the type `T` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound...
   |
62 | impl<T: CodecIF + 'static> Channel<T> {
   |                 +++++++++

T是创建在tokio的task里的,生命周期并没有超出这个task,而 impl<T:CodecIF>只是标记了T的类型,为什么要在类型上标注生命周期呢?这里加上'static 确实可以编译通过,但代价是什么呢?

评论区

写评论
作者 rascalrr 2023-11-16 13:35

感谢大家的讲解,最后还是不传入map给task,而是通过mpsc把task结束的消息传递出来的方式解决这个问题,因此也就不需要'static了。

dakai-chen 2023-11-13 16:46

所以 map 需要是 'static。但是 map 的类型包括 T,所以 T 也要是 'static

--
👇
rascalrr: 对,用Arc传进去的,task是动态创建的,如果60s没有新数据进来,就关停task,并drop掉hashmap中的任务信息。 也考虑过用oneshot或者mpsc通知上级线程,但考虑可能存在漏数据的可能性,所以干脆传了一个hashmap进去。

--
👇
dakai-chen: tokio::spawn 的异步任务还捕获了 map

ribs 2023-11-10 10:42

主要是编译器不清楚你是怎么使用T的,他只知道DashMap包含了Channel,而Channel包含了T,然后DashMap又被转移到spawn里,而T有可能是一个引用,所以认为T寿命不够长,T+'static是生命周期标注,只是人为跟编译器说T不是引用,只要能通过编译,不会对编译结果有任何影响

--
👇
rascalrr: 那像我这种例子,泛型只是为了标注类型,并在task内创建并使用,没有通过参数传递任何引用的话。正确的用法就是 T + 'static 么?

作者 rascalrr 2023-11-10 09:53

那像我这种例子,泛型只是为了标注类型,并在task内创建并使用,没有通过参数传递任何引用的话。正确的用法就是 T + 'static 么?

--
👇
ribs: 可以这么理解,T+'static表示可以一直拥有T,也就是需要转移所有权,因为T的实现也有可能是一个引用,也就是说可以假定不写的时候,有可能是T+'a,所以没办法转移到tokio::spawn的闭包中

作者 rascalrr 2023-11-10 09:41

对,用Arc传进去的,task是动态创建的,如果60s没有新数据进来,就关停task,并drop掉hashmap中的任务信息。 也考虑过用oneshot或者mpsc通知上级线程,但考虑可能存在漏数据的可能性,所以干脆传了一个hashmap进去。

--
👇
dakai-chen: tokio::spawn 的异步任务还捕获了 map

ribs 2023-11-10 01:41

可以这么理解,T+'static表示可以一直拥有T,也就是需要转移所有权,因为T的实现也有可能是一个引用,也就是说可以假定不写的时候,有可能是T+'a,所以没办法转移到tokio::spawn的闭包中

dakai-chen 2023-11-09 17:12

tokio::spawn 的异步任务还捕获了 map

作者 rascalrr 2023-11-09 15:52

谢谢~ 这个我看过了,它说的是函数入参 :T 'static 的情况,和我现在遇到的情况不太相同。

--
👇
Pikachu: https://practice.rs/lifetime/static.html

Pikachu 2023-11-09 14:34

https://practice.rs/lifetime/static.html

1 共 9 条评论, 1 页