存储参数化Future的Timeout结构体时遇编译错误:大小无法确定
关于Tokio Timeout存储到自定义结构体的编译问题
我尝试将tokio::Timeout结构体存储到自定义结构体SockTimeout中,让该结构体拥有它的所有权。我注意到Timeout<T>带有Sized约束,但原以为Timeout能满足编译器要求。
代码示例
use std::future::Future; use std::time::Duration; use tokio::time::{error::Elapsed, timeout, Timeout}; struct SockTimeout { pub timeout: Timeout<dyn Future<Output = ()>>, } #[tokio::main] async fn main() { let when = Duration::from_millis(2000); let my_struct = SockTimeout { timeout: timeout(when, async {}), }; }
编译错误
error[E0277]: the size for values of type `(dyn Future<Output = ()> + 'static)` cannot be known at compilation time --> src/main.rs:30:18 | 30 | pub timeout: Timeout<dyn Future<Output = ()>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Future<Output = ()> + 'static)` note: required by a bound in `tokio::time::Timeout` --> /Users/steve/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.19.2/src/time/timeout.rs:135:24 | 135 | pub struct Timeout<T> { | ^ required by this bound in `tokio::time::Timeout`
问题分析与解决方案
你忽略的核心点是:Timeout<T>的泛型参数T必须满足Sized约束,而dyn Future<Output = ()>是动态大小类型(DST),它的大小在编译时无法确定,自然不满足Sized。你之前尝试用Box包装Timeout本身没用,因为问题出在Timeout内部的T是DST,不是Timeout结构体本身的大小。
解决方法有两种:
1. 用Box包装内部的Future,让T变成Sized类型
把Timeout的泛型参数换成Box<dyn Future<Output = ()>>,因为Box<T>是大小固定的指针类型,满足Sized。同时注意Tokio的timeout要求传入的Future实现Unpin,所以需要用Box::pin包装异步块:
use std::future::Future; use std::time::Duration; use tokio::time::{timeout, Timeout}; struct SockTimeout { pub timeout: Timeout<Box<dyn Future<Output = ()> + 'static>>, } #[tokio::main] async fn main() { let when = Duration::from_millis(2000); let my_struct = SockTimeout { timeout: timeout(when, Box::pin(async {})), }; }
2. 将SockTimeout定义为泛型结构体
通过让SockTimeout携带泛型参数,保留Future的具体类型,这样T自然满足Sized,这种方式没有动态分发的开销:
use std::future::Future; use std::time::Duration; use tokio::time::{timeout, Timeout}; struct SockTimeout<T> where T: Future<Output = ()> + 'static, { pub timeout: Timeout<T>, } #[tokio::main] async fn main() { let when = Duration::from_millis(2000); let my_struct = SockTimeout { timeout: timeout(when, async {}), }; }
内容的提问来源于stack exchange,提问作者Steve McFarlin
相关产品推荐
相关产品推荐

