You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中impl Fn()转fn()报错non-primitive cast,该如何解决?

Rust中impl Fn()转fn()指针报错的原因与解决方法

问题代码与错误

尝试将impl Fn()类型转换为函数指针fn()时触发编译错误:

fn ptr_of(f: impl Fn()) -> fn() {
    f as fn()
}

错误提示:

non-primitive cast: `impl Fn()` as `fn()`

上下文场景

实际要实现的功能代码如下(上述代码是该问题的最简复现):

trait FnExt {
    fn do_smth_with_ptr(&self);
}

impl<T: Fn()> FnExt for T {
    fn do_smth_with_ptr(&self) {
        let ptr: fn() = self as fn(); // 此处触发报错
        todo!();
    }
}

fn example() {
    example2.do_smth_with_ptr();
}

fn example2() {};

原本预期代码能正常运行,因为直接将具体裸函数转换为fn()指针是可行的:

fn test() {}

let ptr = test as fn();

原因分析

impl Fn()代表所有实现了Fn() trait的类型,其中不仅包含可直接转换为fn()指针的裸函数,还包括闭包、带环境的函数对象等类型——这些类型因携带额外环境数据,无法转换为无状态的fn()裸指针。

当你编写impl<T: Fn()> FnExt for T时,T的范围覆盖了所有满足Fn()的类型,包括不能转成fn()的闭包,因此Rust禁止这种强制转换,避免潜在的不安全场景。

而直接执行test as fn()能成功,是因为test是明确的裸函数类型,编译器可以确认转换的安全性。

解决方法

方法1:限制T为可转换为fn()的类型

修改trait实现的类型约束,要求T能转换为fn():

trait FnExt {
    fn do_smth_with_ptr(&self);
}

impl<T: Fn() + Into<fn()>> FnExt for T {
    fn do_smth_with_ptr(&self) {
        let ptr: fn() = (*self).into();
        todo!();
    }
}

fn example() {
    example2.do_smth_with_ptr();
}

fn example2() {};

方法2:仅针对裸函数类型实现trait

如果只需要支持裸函数,直接限定实现的目标类型为fn():

trait FnExt {
    fn do_smth_with_ptr(&self);
}

impl FnExt for fn() {
    fn do_smth_with_ptr(&self) {
        let ptr: fn() = *self;
        todo!();
    }
}

fn example() {
    example2.do_smth_with_ptr();
}

fn example2() {};

方法3:使用不安全的强制转换(不推荐)

如果你能确保所有传入的T都可以安全转换为fn(),可以使用std::mem::transmute进行强制转换,但这种做法存在风险,若传入闭包会导致未定义行为:

trait FnExt {
    fn do_smth_with_ptr(&self);
}

impl<T: Fn()> FnExt for T {
    fn do_smth_with_ptr(&self) {
        unsafe {
            let ptr: fn() = std::mem::transmute(self);
            todo!();
        }
    }
}

fn example() {
    example2.do_smth_with_ptr();
}

fn example2() {};

内容的提问来源于stack exchange,提问作者bnjmn21

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 23:15:54