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

Rust结构体用dyn trait作字段报错,为何String可正常使用?

Rust中dyn Trait与String的大小差异问题

原始代码

trait Animal {}

struct Sheep {}
struct Cow {}

// 为Sheep实现Animal trait
impl Animal for Sheep {}

// 为Cow实现Animal trait
impl Animal for Cow {}

struct Human {
    name: String,
    pet: dyn Animal,
}

impl Human {
    fn new(name: String, animal: dyn Animal) -> Self {
        Human { name, pet: animal }
    }

    fn say_my_name(&self) {
        println!("{}", self.name);
    }
}

fn main() {
    let sheep = Sheep {};
    let human = Human::new(String::from("alex"), sheep);

    human.say_my_name();
}

编译错误信息

error[E0277]: the size for values of type `(dyn Animal + 'static)` cannot be known at compilation time
  --> src/main.rs:18:26
   |
18 |     fn new(name: String, animal: dyn Animal) -> Self {
   |                          ^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `(dyn Animal + 'static)`
help: you can use `impl Trait` as the argument type
   |
18 |     fn new(name: String, animal: impl Animal) -> Self {
   |                                  ~~~~
help: function arguments must have a statically known size, borrowed types always have a known size
   |
18 |     fn new(name: String, animal: &dyn Animal) -> Self {
   |                                  +

error[E0308]: mismatched types
  --> src/main.rs:29:50
   |
29 |     let human = Human::new(String::from("alex"), sheep);
   |                 ----------                       ^^^^^ expected `dyn Animal`, found `Sheep`
   |                 |
   |                 arguments to this function are incorrect
   |
   = note: expected trait object `(dyn Animal + 'static)`
                    found struct `Sheep`
note: associated function defined here
  --> src/main.rs:18:8
   |
18 |     fn new(name: String, animal: dyn Animal) -> Self {
   |        ^^^               ------------------

error[E0277]: the size for values of type `(dyn Animal + 'static)` cannot be known at compilation time
  --> src/main.rs:29:9
   |
29 |     let human = Human::new(String::from("alex"), sheep);
   |         ^^^^^ doesn't have a size known at compile-time
   |
   = help: within `Human`, the trait `Sized` is not implemented for `(dyn Animal + 'static)`
note: required because it appears within the type `Human`
  --> src/main.rs:12:8
   |
12 | struct Human {
   |        ^^^^^
   = note: all local variables must have a statically known size
   = help: unsized locals are gated as an unstable feature

error[E0277]: the size for values of type `(dyn Animal + 'static)` cannot be known at compilation time
  --> src/main.rs:29:50
   |
29 |     let human = Human::new(String::from("alex"), sheep);
   |                                                  ^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `(dyn Animal + 'static)`
   = note: all function arguments must have a statically known size

疑问

编译器提示dyn Animal类型的大小在编译时无法确定,但Human结构体的name字段是String类型,同样涉及动态内容却能正常使用,这是为什么?

修复后的代码

trait Animal {}

struct Sheep {}
struct Cow {}

// 为Sheep实现Animal trait
impl Animal for Sheep {}

// 为Cow实现Animal trait
impl Animal for Cow {}

struct Human {
    name: String,
    pet: Box<dyn Animal>,
}

impl Human {
    fn new(name: String, animal: Box<dyn Animal>) -> Self {
        Human { name, pet: animal }
    }

    fn say_my_name(&self) {
        println!("{}", self.name);
    }
}

fn main() {
    let sheep = Box::new(Sheep {});
    let human = Human::new(String::from("alex"), sheep);

    human.say_my_name();
}

解答

核心差异:String是Sized类型,dyn Animal是非Sized类型

Rust中的String本质是一个固定大小的结构体,它包含三个字段:

  • 指向堆内存的指针
  • 字符串的当前长度
  • 堆内存的容量

这三个字段的大小在编译时完全确定(64位系统下每个字段占8字节,总共24字节),所以String实现了Sized trait,完全符合Rust对结构体字段必须是Sized类型的要求(仅结构体最后一个字段可例外为非Sized,但有额外限制)。

而dyn Animal是 trait 对象,它代表任意实现了Animal trait的类型。不同类型(比如Sheep和Cow)的内存大小可能不同,编译器无法在编译时确定dyn Animal的具体大小,因此它属于非Sized类型,不能直接作为结构体字段或函数参数使用——Rust要求局部变量、函数参数、结构体字段(除特殊情况)必须在编译时确定大小,这样才能分配栈内存。

为什么Box<dyn Animal>能解决问题?

Box<T>是智能指针,它本身是固定大小的(64位系统下占8字节,就是一个堆内存地址)。它将dyn Animal这个非Sized类型存储在堆上,栈上仅保留指向堆内存的指针,这样整个Box<dyn Animal>的大小在编译时是确定的,满足了Rust的Sized要求。

总结:

  • String:栈上固定大小的结构体,指向堆上动态内容,本身是Sized
  • dyn Animal:无固定大小,是非Sized类型,不能直接使用
  • Box<dyn Animal>:栈上固定大小的指针,指向堆上的trait对象,本身是Sized

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 11:21:05