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

如何在Rust中创建可确定大小的函数Trait?解决动态类型大小报错

Rust 动态 trait 对象大小问题及解决思路

问题分析

你遇到的错误核心在于:dyn SimpleSpawner 是动态大小类型(DST),Rust 在编译时无法确定它的大小,而 Vec<T> 要求元素类型 T 必须是编译期大小确定的类型(即实现 Sized trait)。

你在 trait 中添加 Sized 约束的思路不成立——dyn Trait 形式的动态对象本身就不满足 Sized,即使 trait 要求 Sized,也无法让动态对象符合要求。另外,函数指针(fn(...) -> ...)是固定大小的,但它只能兼容无捕获的闭包,无法处理需要捕获环境的闭包,这也是你想要混用函数指针和闭包的矛盾点。

解决方案

下面提供几种可行的解决方式,你可以根据需求选择:

1. 使用 Box 包裹动态 trait 对象(推荐,兼顾灵活性和兼容性)

通过 Box<dyn SimpleSpawner> 将动态对象包装成胖指针(大小固定,包含函数指针和环境数据),这样就能满足 Vec 的 Sized 要求,同时支持函数指针和任意闭包:

#[derive(Clone)]
pub struct RandomTable<T> {
    pub entries: Vec<T>,
}

impl<T> RandomTable<T> {
    pub fn new() -> Self {
        RandomTable {
            entries: Vec::new(),
        }
    }
}

// 去掉 trait 上的 Sized 约束,允许生成动态对象
pub trait SimpleSpawner: Fn(&mut u8) -> u8 {}

// 为所有符合 Fn(&mut u8) -> u8 的类型自动实现 SimpleSpawner
impl<F: Fn(&mut u8) -> u8> SimpleSpawner for F {}

pub fn room_table(map_depth: i32) -> RandomTable<Box<dyn SimpleSpawner>> {
    RandomTable::new()
}

使用示例:

fn example_spawner(x: &mut u8) -> u8 { *x += 1; *x }

let mut table = room_table(1);
// 添加函数指针
table.entries.push(Box::new(example_spawner));
// 添加捕获环境的闭包
let y = 5;
table.entries.push(Box::new(move |x: &mut u8| *x + y));

2. 使用泛型函数返回具体类型

如果不需要动态多态,只需要针对特定类型生成表,可以用泛型:

#[derive(Clone)]
pub struct RandomTable<T> {
    pub entries: Vec<T>,
}

impl<T> RandomTable<T> {
    pub fn new() -> Self {
        RandomTable {
            entries: Vec::new(),
        }
    }
}

pub trait SimpleSpawner: Fn(&mut u8) -> u8 {}
impl<F: Fn(&mut u8) -> u8> SimpleSpawner for F {}

// 返回具体类型的 RandomTable
pub fn room_table<T: SimpleSpawner>(map_depth: i32) -> RandomTable<T> {
    RandomTable::new()
}

这种方式没有动态分配的开销,但灵活性较差,每次调用都需要明确或推导 T 的类型。

3. 仅使用函数指针(无需闭包时)

如果你的场景不需要捕获环境的闭包,直接用函数指针类型即可:

#[derive(Clone)]
pub struct RandomTable<T> {
    pub entries: Vec<T>,
}

impl<T> RandomTable<T> {
    pub fn new() -> Self {
        RandomTable {
            entries: Vec::new(),
        }
    }
}

// 直接定义为函数指针类型
pub type SimpleSpawner = fn(&mut u8) -> u8;

pub fn room_table(map_depth: i32) -> RandomTable<SimpleSpawner> {
    RandomTable::new()
}

这种方式只能添加无捕获的函数或闭包,无法处理需要捕获环境的闭包。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 23:33:12