为什么go和rust语言都舍弃了继承?

Go 和 Rust 都舍弃(或极度弱化)经典的“实现继承”(implementation inheritance),核心原因高度一致:继承在实际工程中带来的问题往往大于它解决的问题,尤其是当项目规模变大、团队变大、时间变长之后。

下面把两门语言的动机和取舍放在一起对比:

维度Go 的做法与动机Rust 的做法与动机共同指向的问题(为什么现代语言集体反感)
是否有 class完全没有 class没有 class,只有 struct + enum + traitclass 通常捆绑了数据 + 行为 + 继承,过于重量级
是否有实现继承完全没有(嵌入只是字段提升,不是继承)完全没有(早期设计阶段移除过 layout 继承提案)是最核心的共同点
多态怎么实现interface + 隐式实现trait + 显式实现(impl Trait for Type)都选择“鸭子类型”或“类型可以实现多个行为”的方式
代码复用主要靠什么组合 + 接口 + 嵌入组合 + Trait + 泛型Composition over Inheritance
父类字段布局问题不存在(因为没有继承)不存在,但如果允许继承会破坏内存安全与零成本抽象继承会让子类布局依赖父类,破坏 Rust 的内存模型
脆弱基类问题不存在不存在修改基类 → 所有子类可能都坏掉
菱形继承/多重继承问题不存在不存在(trait 可以多实现,但没有数据继承)多继承的致命伤(C++ 最典型)
方法查找/分派复杂度非常简单(方法是包级函数,接收者决定)静态分派(泛型)或动态分派(trait object),但没有 vtable 继承链继承链越深,方法解析越复杂
对大型项目/长期维护友好度高(类型之间没有血缘关系,改动影响范围可控)极高(所有权+借用+trait 让耦合更可控)这是 Go/Rust 设计者最在意的点
对性能/零成本抽象影响嵌入是零成本的trait + 泛型是零成本的,trait object 才有运行时开销继承的虚函数表通常有运行时成本

为什么继承被认为“害处大于好处”?(最常见的工程痛点)

  1. 脆弱基类问题(Fragile Base Class Problem)
    基类加/改/删一个 protected 方法或字段 → 所有子类可能都要重新编译/出问题
  2. 紧耦合 & 隐式依赖
    子类严重依赖父类的实现细节,而不是只依赖接口 → 父类一改,子类全炸
  3. 难以理解的深继承链
    第七层子类调用一个方法,到底执行的是哪一层的实现?需要翻很多文件
  4. 多重/菱形继承的灾难(C++ 经典地雷)
  5. 测试/ mock 困难
    继承的类很难替换父类行为(除非重写所有方法)
  6. Rust 特有:破坏内存安全与零开销抽象
    如果允许字段继承,子类的内存布局就依赖父类 → 与借用检查器、Drop 顺序、移动语义严重冲突

Go 和 Rust 分别用什么替代了继承?

想实现的效果Go 的常用写法Rust 的常用写法
代码复用嵌入结构体(embedding)组合 + 写转发方法,或用 derive 宏
“我是某种东西”实现接口(隐式)impl Trait for Type
多态接口值(接口是胖指针)Trait Object(&dyn Trait / Box)
默认实现接口没有默认实现 → 手动写trait 可以提供 default 方法
模板方法模式组合 + 接口回调trait + 泛型 + 默认实现
抽象类没有 → 用接口 + 空结构体技巧没有 → 用 trait + 要求实现某些方法

一句话总结现代语言(Go、Rust、Zig、Nim 等)的共识:

继承是把“是一种”(is-a)关系和“复用实现”强行捆绑在一起,而这两件事其实应该分开处理。

  • “是一种” → 用 接口 / trait 表示(行为契约)
  • “复用实现” → 用 组合 + 委托 更灵活、更可控

所以 Go 和 Rust 不是“忘记”做继承,而是故意不做,它们认为这是对程序员长期友好的选择。

你目前更常用哪一门?在实际项目中遇到过特别想用继承但被语言限制住的场景吗?可以聊聊具体例子~

文章已创建 4725

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部