4 rust
在阅读有关Rust的内容时,我遇到了一个带有数字的示例函数,并返回一个函数,该函数将该数字添加到另一个数字.
fn higher_order_fn_return<'a>(step_value: &'a i32) -> Box<Fn(i32) -> i32 + 'a> {
Box::new(move |x: i32| x + step_value)
}
Run Code Online (Sandbox Code Playgroud)
这里有很多特定于Rust的机制,我无法理解它.我敢肯定其中一些与生命周期管理有关,但必须以这种方式编写的原因使我无法理解.几个问题:
step_value
传入作为参考?Fn(i32) -> i32 + 'a
)?'a
写为generic(<'a>
)但在返回类型(+ 'a
)中"添加" ?move
?禁止提出不止一个问题的禁令,但由于这些都属于"这段代码意味着什么",我不会抱怨.此外,它确实发生了不少古怪的压缩到一个相对较小的,不是非常不寻常的片段.
为什么
step_value
传入作为参考?
不知道.它就是.它可以通过值传递,而不会显着改变代码的语义.但它通过引用传递,这是所有其他与生命相关的问题的原因.
为什么要返回的函数被装箱?
它没有返回一个函数.函数定义为fn
.它正在关闭.问题在于,出于性能原因,每个闭包实际上都是匿名类型的实例(有时称为"Voldemort类型").匿名类型是一个问题,因为您无法命名它们,但您必须命名您的返回类型.
解决这个问题的方法是返回一个特征对象.在这种情况下,它返回一个Fn
.还有FnMut
和FnOnce
.它返回它的盒装因为裸露的特质对象不能被周围按值传递,所以特质对象总是要落后于某种指针(是Box
,&
,Rc
,等).
它们不能通过值传递,因为编译器无法确定它有多大,这使得它们几乎不可能移动它们.在那之后,逻辑系列直接转向"编译器如何实现"领域,这在某种程度上超出了范围.
如何解释编写函数类型的非常规方法(as
Fn(i32) -> i32 + 'a
)?
关于它没有什么不同寻常的.不管怎样,不是Rust,因为这是在Rust中,其他语言的其他方式与之无关.
让我们+ 'a
暂时忽略它,因为那实际上是别的东西.这Fn(i32) -> i32
是重要的部分.拉斯特每一个"可赎回"的东西实现一个或多个的Fn
,FnMut
和FnOnce
特质,这是除锈如何表达的能打电话的东西的想法.parens中的东西是参数,后面的东西->
是返回类型,就像函数一样.
您可以在"何时关闭实现Fn,FnMut和FnOnce?"这一问题中了解有关这些特征的更多信息..
为什么
'a
写为generic(<'a>
)但在返回类型(+ 'a
)中"添加" ?
首先,因为生命周期是类型系统的一部分.因此,它们进入通用参数列表(内部的东西<...>
).
其次,因为编译器必须了解其中的特征对象有多长时间Box
才有效.如果有Box<SomeTrait>
,编译器允许该值存在多长时间?通常,该信息将是该类型的一部分,但如果您使用的是特征,则编译器不知道正在使用哪种类型.记住,你可以做Box<SomeTrait>
出来的任何 Box<T>
地方T
器具SomeTrait
.
在这种情况下,关闭将继续保留step_value
借款,这意味着它不得超过借款的生命周期(即'a
).但如果类型只是 Box<Fn(i32) -> i32>
,编译器就不会有这些信息.因此,有一种语法可以指定无论隐藏在特征对象后面的类型是什么,它都不能超过给定的生命周期.
这+ 'a
就是所说的:"这是一个实现Fn(i32) -> i32
特征的盒装价值,它不能超过生命周期'a
".
移动的意义是什么,移动到底是什么?
通常情况下,编译器会尝试猜测它必须做什么才能使闭包工作,但它并不能始终正确.在可能的情况下,它会尝试借用闭包捕获的东西.所以当你step_value
在闭包内部使用时,编译器通常会借用它.
这不会是一个问题,除了你将关闭退出函数.这种自动借用仅持续功能的寿命,这不够长.要解决此问题step_value
,您可以将其移至闭包中,而不是借用.
你可能想知道的好处.
如果你不写
+ 'a
的Box<Trait + 'a>
,通常会发生什么?
实际上,编译器在这里有一个启发式.默认情况下,每个特征对象都有一个附加的生命周期.它是从包装它的指针继承而来的.所以,&'a Trait
真的&'a (Trait + 'a)
. Box
没有自己的生命周期参数,因此它得到'static
(即 Box<Trait>
是Box<Trait + 'static>
),这意味着默认情况下,盒装特征对象不能包含任何非'static
借用.
归档时间: |
|
查看次数: |
261 次 |
最近记录: |