How do I store a variable of type `impl Trait` in a struct?
这有效:
1 2 3 4 5 6 7 8 9 10 11 | let fut = Arc::new(Mutex::new(Box::pin(async { 1 }))); let mut conn_futures = BTreeMap::new(); // implicitly typed conn_futures.insert(123, fut); if let Some(fut) = conn_futures.get_mut(&123) { let fut = fut.clone(); self.pool.spawn(async move { let mut fut = fut.try_lock().unwrap(); (&mut *fut).await; }); }; |
如何在结构内编写相同的内容;
1 2 3 | struct Foo { conn_futures: BTreeMap<i32, impl Future>, // impl not allow in this position } |
我尝试过:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | use futures::{executor::LocalPool, lock::Mutex, task::SpawnExt, Future}; // 0.3.1 use std::{collections::BTreeMap, pin::Pin, sync::Arc}; struct Foo { conn_futures: BTreeMap<i32, Arc<Mutex<Pin<Box<dyn Future<Output = i32>>>>>>, } fn alternative() { let mut pool = LocalPool::new(); let spawner = pool.spawner(); // Have a structure with the btreemap instead let mut foo = Foo { conn_futures: BTreeMap::new(), }; let fut = Arc::new(Mutex::new(Box::pin(async { 1 }))); foo.conn_futures.insert(123, fut); if let Some(fut) = foo.conn_futures.get_mut(&123) { let fut = fut.clone(); spawner.spawn(async move { let mut fut = fut.try_lock().unwrap(); (&mut *fut).await; }); }; } fn main() { let mut pool = LocalPool::new(); let spawner = pool.spawner(); let fut = Arc::new(Mutex::new(Box::pin(async { 1 }))); let mut conn_futures = BTreeMap::new(); // implicitly typed conn_futures.insert(123, fut); if let Some(fut) = conn_futures.get_mut(&123) { let fut = fut.clone(); spawner.spawn(async move { let mut fut = fut.try_lock().unwrap(); (&mut *fut).await; }); }; } |
游乐场
出现错误
1 2 3 4 5 6 7 8 | error[E0308]: mismatched types --> src/main.rs:17:34 | 17 | foo.conn_futures.insert(123, fut); | ^^^ expected trait core::future::future::Future, found opaque type | = note: expected type `std::sync::Arc<futures_util::lock::mutex::Mutex<std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = i32> + 'static)>>>>` found type `std::sync::Arc<futures_util::lock::mutex::Mutex<std::pin::Pin<std::boxed::Box<impl core::future::future::Future>>>>` |
如何在结构中声明
您不能,真的。
主要解决方案是使用特征对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | use std::fmt::Display; fn make_it() -> impl Display { 2 } struct Example { it: Box<dyn Display>, } impl Example { fn make() -> Self { Example { it: Box::new(make_it()), } } } |
您还可以避免使用关联的函数,而应使用普通函数,而不要使用泛型函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | use std::fmt::Display; fn make_it() -> impl Display { 2 } struct Example< T > { it: T, } impl Example<Box<dyn Display>> { fn make() -> Self { Example { it: Box::new(make_it()), } } } fn make_example() -> Example<impl Display> { Example { it: make_it(), } } |
仅每晚
如果您希望使用不稳定的夜间功能,则可以使用存在性类型(RFC 2071):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // 1.51.0-nightly (2021-01-03 80184183ba0a53aa4f49) #![feature(type_alias_impl_trait)] use std::fmt::Display; type SomeDisplay = impl Display; fn make_it() -> SomeDisplay { 2 } struct Example { it: SomeDisplay, } impl Example { fn make() -> Self { Example { it: make_it() } } } |
或:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // 1.51.0-nightly (2021-01-03 80184183ba0a53aa4f49) #![feature(type_alias_impl_trait)] use std::fmt::Display; fn make_it() -> impl Display { 2 } struct Example< T > { it: T, } type SomeDisplay = impl Display; impl Example<SomeDisplay> { fn make() -> Self { Example { it: make_it() } } } |
另请参见:
- 返回Iterator(或任何其他特征)的正确方法是什么?
- 为什么不能使用impl trait返回多个/条件类型?
- 是否可以在特征定义中将" impl Trait"用作函数的返回类型?
- 是什么使某物成为"特质对象"?
- 在板条箱的API中发布具体类型而不是" impl trait"的好处是什么?
尽管以上建议很有用,但该问题的具体答案是适当地投射
此行
1 | let fut = Arc::new(Mutex::new(Box::pin(async { 1 }))); |
需要更改
1 | let fut = Arc::new(Mutex::new(Box::pin(async { 1 }) as Pin<Box<Future<Output=i32>>> )); |
这将允许人们表达以下struct
1 2 3 | struct Foo { conn_futures: BTreeMap<ChannelId, Arc<Mutex<Pin<Box<dyn Future<Output = i32>>>>>>, } |
,编译器不会抱怨。感谢@Aloso提供的提示
但是,将给出以下错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | error[E0277]: `(dyn core::future::future::Future<Output = i32> + 'static)` cannot be sent between threads safely --> src/main.rs:24:16 | 24 | spawner.spawn(async move { | ^^^^^ `(dyn core::future::future::Future<Output = i32> + 'static)` cannot be sent between threads safely | = help: the trait `std::marker::Send` is not implemented for `(dyn core::future::future::Future<Output = i32> + 'static)` = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn core::future::future::Future<Output = i32> + 'static)>` = note: required because it appears within the type `std::boxed::Box<(dyn core::future::future::Future<Output = i32> + 'static)>` = note: required because it appears within the type `std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = i32> + 'static)>>` = note: required because of the requirements on the impl of `std::marker::Send` for `futures_util::lock::mutex::Mutex<std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = i32> + 'static)>>>` = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures_util::lock::mutex::Mutex<std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = i32> + 'static)>>>>` = note: required because it appears within the type `[static generator@src/main.rs:24:33: 27:10 fut:std::sync::Arc<futures_util::lock::mutex::Mutex<std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = i32> + 'static)>>>> _]` = note: required because it appears within the type `std::future::GenFuture<[static generator@src/main.rs:24:33: 27:10 fut:std::sync::Arc<futures_util::lock::mutex::Mutex<std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = i32> + 'static)>>>> _]>` = note: required because it appears within the type `impl core::future::future::Future` |
这将是一个单独的问题