为什么我会收到错误“const fn 中的函数指针不稳定”,但在包装在 newtype 中时它会消失?

SRU*_*SRU 2 constants rust

这是预期的行为还是编译器错误?

以下代码无法编译。valuesinMyStruct是一个Option因为Vec::new不是 const fn - 但它Option::None是常量(但它仍然不能编译)。

type MyFun = fn(input: u32) -> u32;

struct MyStruct {
    values: Option<Vec<MyFun>>,
}

impl MyStruct {
    pub const fn init() -> Self {
        Self { values: None }
    }
}

fn main() {
    MyStruct::init();
}
Run Code Online (Sandbox Code Playgroud)

操场

error[E0723]: function pointers in const fn are unstable
 --> src/main.rs:9:24
  |
9 |         Self { values: None }
  |                        ^^^^
  |
  = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
  = help: add `#![feature(const_fn)]` to the crate attributes to enable
Run Code Online (Sandbox Code Playgroud)

使用 newtype ( Wrapped) 解决了这个问题。这感觉很奇怪,因为两个示例都是相同的(至少生成的二进制文件应该是相同的)。这种行为是有意的还是一个错误?

这有效:

type MyFun = fn(input: u32) -> u32;

struct Wrapped(Vec<MyFun>);

struct MyStruct {
    values: Option<Wrapped>,
}

impl MyStruct {
    pub const fn init() -> Self {
        Self { values: None }
    }
}

fn main() {
    MyStruct::init();
}
Run Code Online (Sandbox Code Playgroud)

操场

oli*_*obk 6

TLDR:一个错误,但不是你暗示的那个。我们过于积极地为 const fn 中的未来功能敞开大门。

您遇到的错误是为了防止用户编写类似的功能而创建的

const fn foo(f: fn()) {}
Run Code Online (Sandbox Code Playgroud)

因为不可能以f可调用的方式使用。以下功能目前是非法的。

const fn foo(f: fn()) { f() }
Run Code Online (Sandbox Code Playgroud)

在稳定的时候const fn我们不确定它是否应该合法,所以我们先发制人地禁止fnconst fn. 在 const fn 中创建函数指针也是如此。所以

const fn foo() {
    let f: fn() = some_function;
}
Run Code Online (Sandbox Code Playgroud)

是被禁止的,因为我们想保持开门许可

const fn foo() {
    let f: fn() = some_function;
    f();
}
Run Code Online (Sandbox Code Playgroud)

如果你扩展你的用例的代码,你会得到类似的东西

pub const fn init() -> Self {
    let values: Option<fn(u32) -> u32> = None;
    Self { values }
}
Run Code Online (Sandbox Code Playgroud)

你是对的,这是一个错误。虽然不是由于包装和非包装版本之间的差异,而是因为它们None从未真正创建过函数指针。我们只是决定在检查中过于激进,以免错过任何东西。虽然我们可能只想在 const fn 中实现函数指针,但绝对可以在这里创建更好的分析。

包装和非包装版本之间存在差异的原因是我们希望允许

const fn foo(f: fn()) { f() }
Run Code Online (Sandbox Code Playgroud)

但不是

const fn foo(wrapper: Wrapper) { (wrapper.f)() }
Run Code Online (Sandbox Code Playgroud)

因为后者没有在 API 中显示函数指针,所以我们不能做任何魔术来确保函数指针指向一个 const fn。

包装和非包装版本之间的差异可能足以令人困惑,迫使我们放弃我们可以fn如上所述只调用const fn 中的指针并为 const fn 中的指针提出新方案的想法fn