Copyright © 2022-2025 aizws.net · 网站版本: v1.2.6·内部版本: v1.25.2·
页面加载耗时 0.00 毫秒·物理内存 115.0MB ·虚拟内存 1372.1MB
欢迎来到 AI 中文社区(简称 AI 中文社),这里是学习交流 AI 人工智能技术的中文社区。 为了更好的体验,本站推荐使用 Chrome 浏览器。
Rust的Fn trait是个神奇的存在。比如,我们可以写出这样的代码:
struct Closure<F> {
data: (u8, u16),
func: F
}
impl<F> Closure<F>
where F: Fn(&(u8, u16)) -> &u8,
{
fn call(&self) -> &u8 {
(self.func)(&self.data)
}
}
fn do_it(data: &(u8, u16)) -> &u8 { &data.0 }
fn main() {
let clo = Closure{ data: (0, 1), func: do_it };
println!("{}", clo.call());
}
如果我们像在生命周期那一章里一样地去掉这段代码的语法糖,我们会发现一些问题:
struct Closure<F> {
data: (u8, u16),
func: F,
}
impl<F> Closure<F>
// where F: Fn(&'??? (u8, u16)) -> &'??? u8,
{
fn call<'a>(&'a self) -> &'a u8 {
(self.func)(&self.data)
}
}
fn do_it<'b>(data: &'b (u8, u16)) -> &'b u8 { &'b data.0 }
fn main() {
'x: {
let clo = Closure { data: (0, 1), func: do_it };
println!("{}", clo.call());
}
}
我们究竟应该怎么表示F的trait边界里的生命周期呢?这里需要一个生命周期,但是在我们进入call函数之前我们都不知道生命周期的名字!而且,那里的生命周期也是不固定的,&self在那一时间点上是什么生命周期,call就也要是什么生命周期。
这里我们需要借助高阶trait边界(HRTB, Higher-Rank Trait Bounds)的神奇力量了。我们去掉语法糖之后的代码应该是这样的:
where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8,
(其中Fn(a, b, c) -> d本身就是不确定的Fn trait的语法糖)
for<'a>可以读作“对于'a的所有可能选择”,基本上表示一个无限的列表,包含所有F需要满足的trait边界。不过别紧张,除了Fn trait之外我们很少会遇到需要HRTB的场景,而且即使遇到了我们还有一个神奇的语法糖相助。
子类型是类型之间的一种关系,可以让静态类型语言更加地灵活自由。理解这一概念最简单的方法就是参考一些支持继承特性的语言。比如说一个Animal类型有一个eat()方法,Cat类型继承了Animal并且添加了一个meow ...