哪些网站适合推广,天津做网站美工,网站优化怎样的,手机网站设计公原文
Rust异步工作组很高兴地宣布,在实现在特征中使用异步 fn的目标方面取得了重大进度.将在下周发布稳定的Rust1.75版,会包括特征中支持impl Trait注解和async fn.
稳定化
自从RFC#1522在Rust1.26中稳定下来以来,Rust就允许用户按函数的返回类型(一般叫RPIT)编…原文
Rust异步工作组很高兴地宣布,在实现在特征中使用异步 fn的目标方面取得了重大进度.将在下周发布稳定的Rust1.75版,会包括特征中支持impl Trait注解和async fn.
稳定化
自从RFC#1522在Rust1.26中稳定下来以来,Rust就允许用户按函数的返回类型(一般叫RPIT)编写impl Trait.
即该函数返回某种实现特征的类型.这一般来返回闭包,迭代器和其他复杂或无法显式编写的类型.
//给定一个玩家列表,返回在他们的名字上的一个迭代器.
fn player_names(players: [Player]
) - impl IteratorItem String {players.iter().map(|p| p.name)
}从Rust1.75开始,你可在特征(RPITIT)定义和trait impl中使用返回位置的impl Trait.如,你可用它来编写一个返回迭代器的特征方法:
trait Container {fn items(self) - impl IteratorItem Widget;
}
impl Container for MyContainer {fn items(self) - impl IteratorItem Widget {self.items.iter().cloned()}
}则这一切与异步函数有什么关系呢?嗯,异步函数只是返回-impl Future的函数的语法糖.因为在特征中,现在允许这些,还允许你编写使用async fn的特征.
trait HttpService {async fn fetch(self, url: Url) - HtmlBody;
//^^^^^^^^变为:
// fn fetch(self, url: Url) - impl FutureOutput HtmlBody;
}差距在哪?
公开特征中的-impl特征
仍不建议在公开特征和API中普遍使用-impl Trait,因为用户无法对返回类型加限制.如,无法对容器特征通用的编写此函数:
fn print_in_reverse(container: impl Container) {for item in container.items().rev() {//错误:^^^对impl IteratorItemWidget未实现DoubleEndedIterator特征eprintln!({item});}
}尽管某些实现可能会返回实现DoubleEndedIterator的迭代器,但在不定义另一个特征时,泛型代码无法利用它.
未来,打算为此添加一个解决方法.当前,-impl Trait最适合内部特征,或当你确信用户不需要额外约束时.否则,应该考虑使用关联类型.
公开特征中的异步函数
因为async fn解糖为-impl Future,因此有同样限制.事实上,如果今天在公开特征中使用空的异步fn,则会看到警告. 警告:不建议在公开特征中使用async fn,因为无法指定自动特征约束.
异步用户特别感兴趣的是,在返回的未来上的发送约束.因为用户以后无法添加约束,因此错误消息说明你要选择:是否想你的特征与多线程,窃取工作程序一起使用?
好的是,现在有个允许在公开特征中使用异步fn的方法!建议使用trait_variant::make过程宏来让你的用户选择.
该过程宏是由rustlang组织发布的traitvariant包的一部分.在项目中加上cargo add trait-variant.使用:
#[trait_variant::make(HttpService: Send)]
pub trait LocalHttpService {async fn fetch(self, url: Url) - HtmlBody;
}这创建两个版本的特征:用LocalHttpService针对单线程执行器,HttpService针对多线程工作窃取执行器.因为后者更常用,因此此例中名字更短. 它有额外的发送约束:
pub trait HttpService: Send {fn fetch(self,url: Url,) - impl FutureOutput HtmlBody Send;
}该宏适合异步,因为impl Future很少需要发送以外的额外约束,因此可成功为用户准备好.
动态分发
使用-impl Trait和asyncfn的特征不是对象安全的,即不支持动态分发.准备在未来推出的trait-variant包版本中启用动态分发.
未来如何改进
未来,希望允许用户添加自己的约束到impl Trait返回类型,这样更普遍更有用.它还支持异步fn的更高级用法.语法可能如下:
trait HttpService LocalHttpServicefetch(): Send Send;因为这些别名不需要特征作者的支持,因此,因此不需要异步特征的发送变量.但是,这些变量仍会方便用户,因此期望大多数包继续提供它们.
常见问题解答
是否可在特征中使用-impl Trait
对私有特征,可自由使用-impl Trait.对公开特征,最好暂时避免使用它们,除非可预见到用户可能需要的所有约束(此时,你可用#[trait_variant::make],与异步一样). 期望取消来会此限制.
是否仍应使用#[async_trait]宏
你可能要继续使用异步特征的原因有几个: 1,想支持低于1.75的Rust版本. 2,你需要动态分发.
如上,希望在未来版本中启用动态分发.
可在特征中使用async fn吗?有哪些限制
假设,你不用#[async_trait],则完全可以在特征中使用普通的异步 fn.如果想支持多线程运行时,记住使用#[trait_variant::make].
最大限制是类型必须总是决定它实现了特征的发送版本还是非发送版本.它不能在其泛型之一上有条件地实现发送版本.
这可在中间件模式中出现,如,如果T:HttpService,则为HttpService的RequestLimitingServiceT.
为什么我需要#[trait_variant::make]和Send约束
简单情况时,发现你的特征似乎与多线程程序配合得很好.但是,有些模式下不管用.考虑以下:
fn spawn_task(service: impl HttpService static) {tokio::spawn(async move {let url Url::from(https://rustlang.org);let _body service.fetch(url).await;});
}如果特征上没有Send约束,则无法编译,并显示错误:不能在线程间安全发送未来.用Send约束创建特征的变量,可避免发送用户掉此陷阱.
注意,如果未公开你的特征,则不会看到警告,因为如果有问题,总是可自行添加发送约束.
见此博客文章.
我可插件使用async fn和impl Trait吗
是的,你可以在特征和实现中的async fn和-implFuture拼写间自由切换.即使一个形式有发送约束,因此.这样更易使用trait_variant创建的特征.
trait HttpService: Send {fn fetch(self, url: Url)- impl FutureOutput HtmlBody Send;
}
impl HttpService for MyService {async fn fetch(self, url: Url) - HtmlBody {//只要有do_fetch():Send就可以了!self.client.do_fetch(url).await.into_body()}
}为什么这些签名不使用impl Future_
对特征中的-impl Trait,提前用了2024年的抓规则.即今天经常看到的_,在特征中是不必要的,因为已假设中类型来抓输入生命期.
在2024版中,此规则针对所有函数签名.
为什么在使用-impl Trait实现特征时收到细化警告
如果你的实现签名,包含比特征自身更详细的信息,你会收到警告:
pub trait Foo {fn foo(self) - impl Debug;
}
impl Foo for u32 {fn foo(self) - String {
//^^^^^^警告:实现方法签名中的impl Trait与trait方法签名不匹配self.to_string()}
}原因是你可能泄露了更多实现细节.如,如果以下代码编译.
fn main() {//实现者允许使用显示,还是只允许使用特征所说的调试println!({}, 32.foo());
}因为细化了特征实现,它确实可编译,但编译器会要求你在实现上使用#[allow(refining_impl_trait)],确认你打算细化特征接口.
注意,只能在可以命名类型时,才能使用关联类型.一旦impl_trait_in_assoc_type稳定下来,才取消此限制.
这是因为允许知识从未指定签名它们的项目中泄漏的auto trait泄漏.