rust 当异步函数接受可变引用时,为什么不能将其作为字段传递?

xpcnnkqh  于 2022-11-12  发布在  其他
关注(0)|答案(2)|浏览(316)

我正在处理一个将异步函数作为字段的结构,但是当它接受可变引用时就不起作用了。
这是可行的:


# ![allow(dead_code)]

pub struct TestStruct;

struct TestStruct2<F>
where
    F: std::future::Future<Output = ()>,
{
    foo: fn(TestStruct) -> F,
}

async fn foo(_x: TestStruct) {}

# [tokio::main]

async fn main() {
    let _s = TestStruct2 { foo };
}

这是行不通的:


# ![allow(dead_code)]

pub struct TestStruct;

struct TestStruct2<F>
where
    F: std::future::Future<Output = ()>,
{
    foo: fn(&mut TestStruct) -> F,
}

async fn foo(_x: &mut TestStruct) {}

# [tokio::main]

async fn main() {
    let _s = TestStruct2 { foo }; //error here
}

错误:

mismatched types
expected fn pointer `for<'r> fn(&'r mut TestStruct) -> _`     
found fn item `for<'r> fn(&'r mut TestStruct) -> impl std::future::Future<Output = ()> {foo}`

有人能向我解释为什么会发生这种情况,我能做些什么吗?

inb24sb2

inb24sb21#

问题不在于mut,而在于引用和它的生存期。根据the Asynchronous Programming in Rust bookasync函数的返回值的生存期受其参数的生存期限制。您的TestStruct2::foo定义不接受这一点。要解决这一问题,您可以显式地将此生存期添加到F中:

struct TestStruct2<'a, F>
where
    F: std::future::Future<Output = ()> + 'a,
{
    foo: fn(&'a mut TestStruct) -> F,
}
of1yzvn4

of1yzvn42#

看起来foo的返回类型有一个隐式的+ 'a绑定,其中'a&mut TestStruct中的匿名生存期。
只需将foo反语法化为显式impl Trait类型和async块即可解决此问题。


# ![allow(dead_code)]

pub struct TestStruct;

struct TestStruct2<F>
where
    F: std::future::Future<Output = ()>,
{
    foo: fn(&mut TestStruct) -> F,
}

fn foo(_x: &mut TestStruct) -> impl std::future::Future<Output = ()> {
    async {}
}

# [tokio::main]

async fn main() {
    let _s = TestStruct2 { foo };
}

然而,当我们试图使用async块中的引用时,错误再次弹出(看起来编译器将所有参数从async fn块移到了隐藏的async块中)。
第一个
如果我们应用编译器的建议,那么我们又回到了起点:
第一个
我们可以通过在TestStruct2中添加一个lifetime参数并在适当的地方使用它来修复这个问题(我们也可以将foo恢复到它的原始形式)。


# ![allow(dead_code)]

pub struct TestStruct;

struct TestStruct2<'a, F>
where
    F: std::future::Future<Output = ()> + 'a,
{
    foo: fn(&'a mut TestStruct) -> F,
}

async fn foo(_x: &mut TestStruct) {}

# [tokio::main]

async fn main() {
    let s = TestStruct2 { foo };
    let mut t = TestStruct;
    (s.foo)(&mut t).await;
}

相关问题