gpt4 book ai didi

rust - 如何理解这个返回另一个函数的Rust函数?

转载 作者:行者123 更新时间:2023-11-29 07:52:36 25 4
gpt4 key购买 nike

关于Rust的reading时,我遇到了一个示例函数,该函数接受一个数字并返回一个将该数字添加到另一个数字的函数。

fn higher_order_fn_return<'a>(step_value: &'a i32) -> Box<Fn(i32) -> i32 + 'a> {
Box::new(move |x: i32| x + step_value)
}

这里有太多针对Rust的机制,我无法理解。我敢肯定,其中一些与生命周期管理有关,但是我必须以这种方式编写它的原因使我难以理解。几个问题:
  • 为什么将step_value作为引用传递?
  • 为什么将返回的函数装箱?
  • 如何解释写函数类型的非常规方式(如Fn(i32) -> i32 + 'a)?
  • 为什么将'a编写为泛型(<'a>),但在返回类型(+ 'a)中“添加”呢?
  • move的含义是什么,在这里被移动了什么?
  • 最佳答案

    禁止提出一个以上的问题,但是由于所有这些都属于“这段代码的含义”,因此我不会提示。同样,它确实将相当多的怪异现象压缩成一个相对较小的,不是非常不寻常的片段。

    Why is step_value passed in as a reference?



    不知道。就是这样它可以按值传递,而不会显着改变代码的语义。但这是通过引用传递的,这也是所有其他与生命相关的问题的原因。

    Why is the function being returned boxed?



    它没有返回函数。函数由 fn定义。它正在返回一个关闭。这里的问题是,由于性能原因,每个闭包实际上都是匿名类型(有时称为“Voldemort类型”)的实例。匿名类型是一个问题,因为您无法命名它们,但必须命名返回类型。

    解决此问题的方法是返回一个特征对象。在这种情况下,它将返回 Fn。还有 FnMutFnOnce。它返回装箱,因为裸特征对象无法按值传递,因此特征对象始终必须位于某种指针之后(例如 Box&Rc等)。

    它们不能按值传递,因为编译器无法计算出它的大小,这使得将它们移动几乎是不可能的。之后,逻辑逻辑直接转移到“编译器的实现方式”领域,此处超出了范围。

    How to interpret the unconventional way to write a function type (as Fn(i32) -> i32 + 'a) ?



    没有什么非常规的。无论如何,这并不适用于Rust,而且因为它是在Rust中使用的,所以其他语言的用法也无关紧要。

    让我们暂时忽略 + 'a,因为实际上这是另外一回事。 Fn(i32) -> i32是重要的部分。 Rust中的每个“可调用”事物都实现 FnFnMutFnOnce特性中的一个或多个,这就是Rust表示能够调用某些东西的想法。括号内的内容是参数, ->之后的内容是返回类型,就像函数一样。

    您可以在问题 "When does a closure implement Fn, FnMut and FnOnce?"中了解有关这些特征的更多信息。

    Why is 'a written as a generic (<'a>) but "added" in the return type (+ 'a) ?



    首先,因为生存期是类型系统的一部分。因此,它们进入通用参数列表( <...>内的东西)。

    其次,因为编译器必须了解 Box内的特征对象将对有效期多长时间。如果您有 Box<SomeTrait>,则允许编译器让该值存在多长时间?通常,该信息将是类型的一部分,但是如果您使用的是特征,则编译器将不知道所使用的是哪种类型。请记住,您可以在 Box<SomeTrait>实现 Box<T>的任何 T中制作一个 SomeTrait

    在这种情况下,闭包将保留 step_value借用,这意味着它不能超过该借用的生存期(即 'a)。但是,如果类型只是 Box<Fn(i32) -> i32>,则编译器将没有该信息。因此,可以使用语法来指定,无论隐藏在trait对象后面的类型是什么,它都不能超过给定的生存期。

    这就是 + 'a所说的:“这是一个实现 Fn(i32) -> i32特性的带框值,它不能超过 'a的生命周期”。

    What is the meaning of the move and what is being moved here?



    通常,编译器会尝试猜测要使闭包工作所需执行的操作,但并非总能正确完成。在可能的情况下,它会尝试借由闭包捕获的内容。因此,当您在闭包内部使用 step_value时,编译器通常只会借用它。

    除非您要从函数中返回闭包,否则这不是问题。这种自动借用只会持续到函数的整个生命周期,而生命周期还不够长。要解决此问题,您无需将 step_value借用,而是可以将其移动到闭包中。

    您可能想知道的额外奖励。

    If you don't write the + 'a in Box<Trait + 'a>, what would normally happen?



    实际上,编译器在这里具有试探性。默认情况下,每个特征对象都有一个附加的生存期。它是从包装它的指针继承的。因此, &'a Trait实际上是 &'a (Trait + 'a)Box没有自己的生命周期参数,因此它会获得 'static(即 Box<Trait>Box<Trait + 'static>),这意味着默认情况下,装箱的特征对象不能包含任何非 'static借位。

    关于rust - 如何理解这个返回另一个函数的Rust函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45330614/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com