Asynchronous 在需要trait对象的上下文中使用借用参数的异步函数

Asynchronous 在需要trait对象的上下文中使用借用参数的异步函数,asynchronous,rust,Asynchronous,Rust,我最近开始在Rust中使用异步流,我发现自己一直处于想在流的实现中使用异步函数的情况。异步函数通常来自我不控制的库,但为了示例起见,假设它们如下所示: async fn bar_str(s: &str) -> String { s.to_string() } async fn bar_string(s: String) -> String { s } use std::fmt::Debug; trait Foo<'a> { fn fo

我最近开始在Rust中使用异步流,我发现自己一直处于想在
流的实现中使用异步函数的情况。异步函数通常来自我不控制的库,但为了示例起见,假设它们如下所示:

async fn bar_str(s: &str) -> String {
    s.to_string()
}

async fn bar_string(s: String) -> String {
    s
}
use std::fmt::Debug;

trait Foo<'a> {
    fn foo(self) -> Box<dyn Debug + 'a>;
}

impl Foo<'static> for String {
    fn foo(self) -> Box<dyn Debug> {
        Box::new(self)
    }
}

impl<'a> Foo<'a> for &'a str {
    fn foo(self) -> Box<dyn Debug + 'a> {
        Box::new(self)
    }
}
同样为了简单起见,假设我只是尝试使用这些函数来实现如下特征(不涉及实际的流内容):

对于异步函数借用的情况,它不会

impl Foo for &str {
    fn bar(self) -> Box<Future<Output = String>> {
        Box::new(bar_str(self))
    }
}
我可以理解这是一个问题的原因,并且我理解
async fn
语法为类似这样的借用参数提供了特殊处理(尽管我不知道它实际上是如何被检查、删除的,等等)


我的问题是,在这种情况下,通常最好的做法是什么。有什么方法可以重现我在非
async-fn
代码中所做的神奇的
async-fn
代码吗?我是否应该避免借用异步函数(如果可以的话,因为这通常是我没有做出的决定)?在我目前编写的代码中,我很乐意使用实验性的或不一定是未来验证的解决方案,如果它们能使读写这种东西变得更好。

我认为问题不在于
异步
,而在于
框中的
东西。事实上,它可以通过一个简单的特征复制:

use std::fmt::Debug;

trait Foo {
    fn foo(self) -> Box<dyn Debug>;
}

impl Foo for String {
    fn foo(self) -> Box<dyn Debug> {
        Box::new(self)
    }
}

impl Foo for &str {
    fn foo(self) -> Box<dyn Debug> {
        Box::new(self) // <--- Error here (line 15)
    }
}
但这意味着我们只能将类型为“static
”的值装箱。而且
&'a str
不是静态类型,因此不能以这种方式装箱

像往常一样,如果可能的话,简单的解决办法是克隆。这是编译的,它不太难看:

impl Foo for &str {
    fn foo(self) -> Box<dyn Debug> {
        Box::new(self.to_owned())
    }
}
如果您确实想要或需要借用,那么装箱的dyn对象必须在某个生命周期内是通用的。你必须改变你的特质的回报类型,比如:

async fn bar_str(s: &str) -> String {
    s.to_string()
}

async fn bar_string(s: String) -> String {
    s
}
use std::fmt::Debug;

trait Foo<'a> {
    fn foo(self) -> Box<dyn Debug + 'a>;
}

impl Foo<'static> for String {
    fn foo(self) -> Box<dyn Debug> {
        Box::new(self)
    }
}

impl<'a> Foo<'a> for &'a str {
    fn foo(self) -> Box<dyn Debug + 'a> {
        Box::new(self)
    }
}
使用std::fmt::Debug;
性状Foo;
}

impl Foo Foo Box
本身不是一个静态类型,但该类型本身的生存期为
'a

谢谢,这很有帮助,但我担心我可能过度最小化了,这会进一步最小化。例如,我不能克隆,因为我需要调用需要引用的函数(我不控制)。我还尝试添加一个显式的生存期参数,但遇到了问题,但我将仔细研究如何使其起作用。@TravisBrown:是的,
async
问题通常是几个问题,一个一个地叠在另一个上。无论如何,您的原始代码具有显式生命周期。也许你可以发布一个游乐场链接来显示新的问题?刚刚确认,在显式生命周期中线程确实有效(至少在我在真实代码中遇到过的一个地方)!我一定是太快放弃了。谢谢你的澄清。
impl Foo for &str {
    fn foo(self) -> Box<dyn Debug> {
        Box::new(self.to_owned())
    }
}
impl Foo for &'static str {
    fn foo(self) -> Box<dyn Debug> {
        Box::new(self)
    }
}
use std::fmt::Debug;

trait Foo<'a> {
    fn foo(self) -> Box<dyn Debug + 'a>;
}

impl Foo<'static> for String {
    fn foo(self) -> Box<dyn Debug> {
        Box::new(self)
    }
}

impl<'a> Foo<'a> for &'a str {
    fn foo(self) -> Box<dyn Debug + 'a> {
        Box::new(self)
    }
}