如何在结构中存储类型为"impl Trait"的变量?



这有效:

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;
});
};

如何在结构中编写相同的东西;conn_futures的类型是什么?根据编译器的说法,它是BTreeMap<i32, impl Future>的,但是没有办法在结构中编写它:

struct Foo {
conn_futures: BTreeMap<i32, impl Future>, // impl not allow in this position
}

我试过这个:

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;
});
};
}

操场

并得到一个错误

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>>>>`

如何在结构中声明conn_futures的类型?

你不能,真的。impl Trait创建一个匿名的、不可命名的类型。这意味着您不能声明具有显式类型的变量。

主要解决方案是使用特征对象

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()),
}
}
}

您还可以避免使用关联的函数,而改用普通函数,并结合使用泛型:

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.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.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() }
}
}

另请参阅:

  • 返回迭代器(或任何其他特征(的正确方法是什么?
  • 为什么 impl trait 不能用于返回多个/条件类型?
  • 是否可以在特征定义中使用"impl Trait"作为函数的返回类型?
  • 是什么使某物成为"特征对象"?
  • 在板条箱的 API 中发布具体类型而不是"impl trait"有什么好处?

尽管上述建议很有用,但该问题的具体答案是适当地投射Pin<Box<Future>>>

此行

let fut = Arc::new(Mutex::new(Box::pin(async { 1 })));

需要改变

let fut = Arc::new(Mutex::new(Box::pin(async { 1 }) as Pin<Box<Future<Output=i32>>> ));

这将允许人们表达以下结构

struct Foo {
conn_futures: BTreeMap<ChannelId, Arc<Mutex<Pin<Box<dyn Future<Output = i32>>>>>>,
}

编译器不会抱怨。感谢@Aloso的提示

但是,给出了以下错误

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`

这将是一个单独的问题

最新更新