TL; DR: ошибка, но не та, на которую вы намекали. Мы чересчур агрессивно держим дверь открытой для будущих функций в const fn.
Ошибка, с которой вы сталкиваетесь, была создана для того, чтобы пользователи не могли писать такие функции, как
const fn foo(f: fn()) {}
, поскольку это невозможно использовать f
вызываемым способом. Следующая функция сейчас недопустима.
const fn foo(f: fn()) { f() }
Во время стабилизации const fn
мы не были уверены, должна ли она быть допустимой, поэтому мы превентивно запретили указатели fn
в const fn
. То же самое касается создания указателей на функции внутри const fn. Итак,
const fn foo() {
let f: fn() = some_function;
}
запрещено, потому что мы хотим оставить дверь открытой для разрешения
const fn foo() {
let f: fn() = some_function;
f();
}
Если вы расширите код своего варианта использования, вы получите что-то вроде
pub const fn init() -> Self {
let values: Option<fn(u32) -> u32> = None;
Self { values }
}
Вы правы в том, что это ошибка. Хотя не из-за разницы между версией с оболочкой и без оболочки, а потому, что None
на самом деле никогда не создает указатель на функцию. Мы просто решили действовать чересчур агрессивно, чтобы ничего не упустить. Здесь определенно можно провести лучший анализ, хотя мы можем просто реализовать указатели на функции в const fn.
Причина, по которой существует разница между версией с оболочкой и без оболочки, заключается в том, что мы хотим разрешить
const fn foo(f: fn()) { f() }
, но не
const fn foo(wrapper: Wrapper) { (wrapper.f)() }
, поскольку последний не показывает указатель на функцию в API, поэтому мы не можем делать никаких магий c, чтобы гарантировать, что указатель на функцию указывает на const fn.
Разница между обернутой и не обернутой версией может быть достаточно запутанной, чтобы заставить нас отказаться от идеи, что мы можем просто вызвать fn
указатели в const fn, как описано выше, и прийти вверх с новой схемой для fn
указателей в const fn.