让我们假设有一个性状Foo:

trait Foo {
   type Future: Future<Output = ()>;
   fn bar(&self, a: &str) -> Self::Future;
}

其具有获取对自身的引用以及对字符串片段的引用并返回Future的所需方法bar.

让我们为引用字符串片并返回相应future 的任何fn实现Foo.

impl<Fut: Future<Output = ()>> Foo for fn(&str) -> Fut {
   type Future = Fut;
   fn bar(&self, a: &str) -> Self::Future {
      self(a)
   }
}

现在,让我们try 在引用字符串片的async fn上调用bar.

async fn test(a: &str) {
    /* ... */
}

#[tokio::main]
async fn main() {
    Foo::bar(&(test as fn(&str) -> _), "Hello world");
}

尽管test具有正确的函数签名,并且它返回正确的future ,但从test_functionfn(&str) -> _的类型强制转换失败.

error[E0605]: non-primitive cast: `for<'a> fn(&'a str) -> impl Future<Output = ()> {test}` as `for<'a> fn(&'a str) -> _`
  --> src/main.rs:21:15
   |
21 |     Foo::bar(&(test as fn(&str) -> _), "Hello world");
   |               ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast

Try it yourself

根据我的理解,这是将从test返回的impl Futere绑定到参数生存期a的原因.

我能想到的唯一非夜间解决方案是在这一特征中引入一生.

trait Foo<'a> {
   type Future: Future<Output = ()> + 'a;
   fn bar(&self, a: &'a str) -> Self::Future;
}

impl<'a, Fut: Future<Output = ()> + 'a> Foo<'a> for fn(&'a str) -> Fut {
   type Future = Fut;
   fn bar(&self, a: &str) -> Self::Future {
      self(a)
   }
}

通过《夜间》中的一些非常实验性的功能,我想出了这样的 idea :

#![feature(return_position_impl_trait_in_trait)]
use std::future::Future;

trait Foo {
   fn bar<'a>(&self, a: &'a str) -> impl Future<Output = ()> + 'a;
}

impl<Fut> Foo for fn(&str) -> Fut
where 
    for<'a> Fut: Future<Output = ()> + 'a,
{
   fn bar(&self, a: &str) -> Fut {
      self(a)
   }
}

async fn test(a: &str) {
    /* ... */
}

#[tokio::main]
async fn main() {
    Foo::bar(&(test as fn(&str) -> _), "Hello world");
} 

Try it yourself

但这仍然会导致相同的非基元类型转换错误.

推荐答案

每当我遇到像这样奇怪的一生问题时,我的第一react 总是明确地写出一生,看看我们在哪里搞砸了.

让我们go 写下我们期望的生命周期 :

trait Foo<'s> {
   type Future: Future<Output = ()>;
   fn bar<'t>(&'t self, a: &'s str) -> Self::Future;
}

impl<'s, Fut: Future<Output = ()>> Foo<'s> for fn(&'s str) -> Fut {
   type Future = Fut;
   fn bar<'t>(&'t self, a: &'s str) -> Self::Future {
      self(a)
   }
}

现在,如果我们将as fn(&str) -> _更改为as fn(_) -> _,我们的代码*就可以工作了:

async fn test(a: &str) {
    /* ... */
}

#[tokio::main]
async fn main() {
    Foo::bar(&(test as fn(_) -> _), "Hello world");
}

等等,什么?这真的很奇怪,对吧?为什么我们只是显式地写出了生命周期,现在我们的程序就可以工作了?我们为什么需要这as fn(_) -> _美元?为什么我们不能用as fn(&str) -> _呢?老实说,我也不知道.不管原因如何,希望这个答案能帮助你.

Rust相关问答推荐

为什么我们不能通过指针算法将Rust原始指针指向任意地址?'

为什么拥有的trait对象的相等运算符移动了正确的操作数?

使用元组执行条件分支的正确方法

Box::new()会从一个堆栈复制到另一个堆吗?

通过解引用将值移出Box(以及它被脱糖到什么地方)?

为什么reqwest以文本形式下载二进制文件?

在使用AWS SDK for Rust时,如何使用硬编码访问密钥ID和密钥凭据?

什么是`&;[][..]`铁 rust 里的刻薄?

类型生命周期绑定的目的是什么?

tokio::sync::broadcast::Receiver 不是克隆

write_buffer 不写入缓冲区而是输出零 WGPU

如何在 Rust 中打印 let-else 语句中的错误?

Sized问题的动态调度迭代器Rust

为什么需要同时为值和引用实现`From`?方法不应该自动解引用或borrow 吗?(2023-06-16)

Rust 编译器不统一在 if let 表达式的分支中都 impl Future 的类型

如何递归传递闭包作为参数?

使用部分键从 Hashmap 中检索值

在 Rust 中为泛型 struct 编写一次特征绑定

在 Traits 函数中设置生命周期的问题

为什么 Rust 标准库同时为 Thing 和 &Thing 实现特征?