Rust: Rust 特征(Traits):定义共享行为

最后更新:2026-08-26

特征(trait)是 Rust 的"接口"——它定义了一组方法签名,不同类型可以实现同一个 trait,从而共享相同的行为约定。

如果说具体类型是"这东西是什么",那 trait 就是"这东西能做什么"。就像 USB-C 接口——无论是手机、笔记本还是平板,只要支持 USB-C,插上就能充电。设备内部千差万别,但对外承诺的行为是一致的。


1. 你将学到


2. 概念图解

以下 Mermaid 图展示 trait 从定义到为各类型实现再到多态调用的完整关系链:

100%
graph LR
    A["trait UsbCCharge"] -->|定义行为契约| B["fn charge(&self)"]
    A --> C["fn voltage(&self) -> u32"]
    A --> D["fn charge_time(&self) -> String"]
    B --> E["impl for Phone<br/>charge: 18W"]
    B --> F["impl for Laptop<br/>charge: 65W"]
    B --> G["impl for Tablet<br/>charge: 30W"]
    E --> H["phone.charge()"]
    F --> I["laptop.charge()"]
    G --> J["tablet.charge()"]
    H --> K["多态调用<br/>同一 trait 接口<br/>不同类型行为各异"]
    I --> K
    J --> K

3. 通用充电器的故事

(1) 痛苦:每个设备都有自己的充电方法

Leo (Leo) 是一家电子产品公司的架构师。公司产品线越来越多:Phone、Laptop、Tablet,每个设备都有自己的充电逻辑。

最开始他为每个设备单独写充电代码:

RUST
struct Phone;
struct Laptop;
struct Tablet;

impl Phone {
    fn charge(&self) {
        println!("Phone: charging via USB-C at 18W");
    }
}

impl Laptop {
    fn charge(&self) {
        println!("Laptop: charging via USB-C at 65W");
    }
}

impl Tablet {
    fn charge(&self) {
        println!("Tablet: charging via USB-C at 30W");
    }
}

fn main() {
    let phone = Phone;
    let laptop = Laptop;
    let tablet = Tablet;

    phone.charge();
    laptop.charge();
    tablet.charge();
}

三个结构体各自有一个 charge 方法,方法名相同,签名相同,但彼此之间没有任何"约定"关系。如果要写一个"通用充电站"函数来给任意设备充电——做不到。每个设备类型都是独立的,没有共同的抽象层。

(2) 更复杂的需求:批量充电

产品经理要求开发一个"通用充电站",能同时给多个不同类型的设备充电:

RUST
// 这种代码无法编译——参数类型不确定
// fn charge_all_devices(devices: ???) {
//     for device in devices {
//         device.charge();
//     }
// }

没有 trait,charge_all_devices 无法接受混合类型的集合。要么为每种类型重载一个函数,要么放弃。

(3) Rust trait 的方案

RUST
// Define a trait: a shared behavior contract
trait UsbCCharge {
    fn charge(&self);
    fn voltage(&self) -> u32 { 18 }  // Default method with default voltage
}

struct Phone;
struct Laptop;
struct Tablet;

impl UsbCCharge for Phone {
    fn charge(&self) {
        println!("Phone: charging via USB-C at {}W", self.voltage());
    }
    // voltage() uses the default (18W)
}

impl UsbCCharge for Laptop {
    fn charge(&self) {
        println!("Laptop: charging via USB-C at {}W", self.voltage());
    }
    fn voltage(&self) -> u32 { 65 }  // Override default
}

impl UsbCCharge for Tablet {
    fn charge(&self) {
        println!("Tablet: charging via USB-C at {}W", self.voltage());
    }
    fn voltage(&self) -> u32 { 30 }  // Override default
}

// Generic function: accepts any type that implements UsbCCharge
fn charge_device<T: UsbCCharge>(device: &T) {
    device.charge();
}

fn main() {
    charge_device(&Phone);
    charge_device(&Laptop);
    charge_device(&Tablet);
}

输出:

TEXT 📖 仅展示
Phone: charging via USB-C at 18W
Laptop: charging via USB-C at 65W
Tablet: charging via USB-C at 30W

trait UsbCCharge 定义了一个"充电行为契约"。任何实现了这个 trait 的类型都可以被 charge_device 接受。voltage() 有默认实现(18W),但 Laptop 和 Tablet 选择覆盖它。这就是 trait 的核心价值——定义共享行为,允许差异化的实现


4. 核心概念

(1) Trait 体系总览

100%
graph TB
    A[Rust Trait System] --> B[Trait Definition]
    A --> C[Implementing Traits]
    A --> D[Derivable Traits]
    A --> E[Trait as Parameters]
    A --> F[Trait Objects]
    A --> G[Trait Inheritance]

    B --> B1["trait Name { fn method(&self); }"]
    C --> C1["impl TraitName for MyType { ... }"]
    C --> C2["Default methods in trait"]

    D --> D1["#[derive(Debug, Clone, Copy, PartialEq)]"]
    D --> D2["Compiler auto-generates implementation"]

    E --> E1["fn foo(x: impl Trait)"]
    E --> E2["fn foo<T: Trait>(x: T)"]
    E --> E3["fn foo<T>(x: T) where T: Trait"]

    F --> F1["Box<dyn Trait>"]
    F --> F2["Runtime dispatch (vtable)"]

    G --> G1["trait A: SuperTrait { }"]
    G --> G2["Inherits methods from SuperTrait"]

(2) 静态分发 vs 动态分发

特性 泛型约束 T: Trait / impl Trait Trait 对象 dyn Trait
分发时机 编译时(静态分发) 运行时(动态分发)
实现方式 单态化——每类型生成独立代码 虚表(vtable)——指针间接调用
性能 零开销(可内联) 有间接调用开销
二进制体积 较大(每类型一份) 较小(一份代码)
类型要求 调用时确定具体类型 类型可以不同,只要实现同一 trait
适用场景 性能敏感、类型在编译期已知 需要异构集合、类型在运行时决定

(3) 常用可派生 Trait

Trait 作用 自动生成的行为
Debug 格式化输出 {:?} 生成调试输出,打印结构体字段名和值
Clone 显式复制 .clone() 生成 clone 方法,逐个字段复制
Copy 隐式复制(按位拷贝) 赋值时不转移所有权,而是复制
PartialEq 相等比较 == / != 生成 eq 方法,逐个字段比较
Eq 完全等价(数学等价关系) 基于 PartialEq,额外保证自反性
Hash 哈希计算 生成 hash 方法,逐个字段计算哈希值
Default 默认值 生成 default 方法,每个字段用其默认值

(4) Trait 约束组合方式速查

约束方式 语法 适用场景 示例
内联单约束 fn foo<T: Trait>(x: T) 简单单约束 fn charge<T: UsbCCharge>(d: &T)
内联多约束 fn foo<T: Trait1 + Trait2>(x: T) 多个约束 fn describe<T: Debug + UsbCCharge>(d: &T)
where 子句 fn foo<T>(x: T) where T: Trait 复杂约束、多类型参数 where T: UsbCCharge, U: Debug
impl Trait fn foo(x: impl Trait) 简洁语法糖 fn plug(d: &impl USBDevice)
impl Trait + fn foo(x: impl Trait1 + Trait2) 简洁多约束 fn describe(d: &(impl USBDevice + Debug))

5. Trait 示例

▶ 示例 1:Trait 定义与默认方法——设备充电器(难度 ⭐)

RUST
// ============================================
// Trait definition with default methods
// ============================================

// Define a trait: any device that can charge via USB-C
trait UsbCCharge {
    // Required method: must be implemented
    fn charge(&self);

    // Default method: implementor MAY override
    fn voltage(&self) -> u32 {
        18  // Default: standard USB-C 18W
    }

    // Another default method using self.voltage()
    fn charge_time(&self, battery_capacity_mah: u32) -> String {
        let hours = battery_capacity_mah as f64 / (self.voltage() as f64 * 1000.0 / 5.0);
        format!("{:.1} hours to full charge", hours)
    }
}

struct Phone;
struct Laptop;
struct Tablet;

impl UsbCCharge for Phone {
    fn charge(&self) {
        // Uses the default voltage() -> 18W
        println!("Phone: charging at {}W (standard speed)", self.voltage());
    }
    // voltage() uses default, charge_time() uses default
}

impl UsbCCharge for Laptop {
    fn charge(&self) {
        println!("Laptop: charging at {}W (fast charging)", self.voltage());
    }

    fn voltage(&self) -> u32 {
        65  // Laptop needs more power
    }
}

impl UsbCCharge for Tablet {
    fn charge(&self) {
        println!("Tablet: charging at {}W (medium speed)", self.voltage());
    }

    fn voltage(&self) -> u32 {
        30
    }
}

fn main() {
    let phone = Phone;
    let laptop = Laptop;
    let tablet = Tablet;

    phone.charge();
    println!("  -> {}", phone.charge_time(3000));

    laptop.charge();
    println!("  -> {}", laptop.charge_time(6000));

    tablet.charge();
    println!("  -> {}", tablet.charge_time(5000));
}

输出:

TEXT 📖 仅展示
Phone: charging at 18W (standard speed)
  -> 0.8 hours to full charge
Laptop: charging at 65W (fast charging)
  -> 0.5 hours to full charge
Tablet: charging at 30W (medium speed)
  -> 0.8 hours to full charge

UsbCCharge trait 中,charge()必需方法——每个实现者都必须提供。voltage()charge_time()默认方法——提供默认实现,实现者可以选择覆盖也可以直接使用。Phone 只实现了 charge(),其余两个方法都用默认实现;Laptop 覆盖了 voltage(),其余用默认。


▶ 示例 2:派生 Trait——调试、克隆与比较(难度 ⭐⭐)

RUST
// ============================================
// Derivable traits: Debug, Clone, Copy, PartialEq
// ============================================

// Without deriving, none of these operations would work
#[derive(Debug, Clone, Copy, PartialEq)]
struct ChargerSpec {
    brand: &'static str,
    watts: u32,
    usb_c: bool,
}

// PartialEq is needed for this custom type
#[derive(Debug, Clone, PartialEq)]
struct Device {
    name: String,
    required_watts: u32,
}

fn main() {
    // --- Debug: pretty-print with {:?} ---
    let spec1 = ChargerSpec { brand: "Anker", watts: 65, usb_c: true };
    println!("Debug: {:?}", spec1);
    println!("Pretty: {:#?}", spec1);

    // --- Clone: explicit copy ---
    let spec2 = spec1.clone();   // spec1 is still valid
    println!("Cloned: {:?}", spec2);

    // --- Copy: implicit copy (only if Copy is derived) ---
    let spec3 = spec1;            // spec1 is STILL valid because ChargerSpec is Copy!
    println!("Copied (implicit): {:?}", spec3);
    println!("Original still valid: {:?}", spec1);  // Works!

    // --- PartialEq: equality comparison ---
    let spec_a = ChargerSpec { brand: "Anker", watts: 65, usb_c: true };
    let spec_b = ChargerSpec { brand: "Anker", watts: 65, usb_c: true };
    let spec_c = ChargerSpec { brand: "Baseus", watts: 65, usb_c: true };

    println!("spec_a == spec_b: {}", spec_a == spec_b);  // true
    println!("spec_a == spec_c: {}", spec_a == spec_c);  // false (brand differs)
    println!("spec_a != spec_c: {}", spec_a != spec_c);  // true

    // --- Practical: filtering devices ---
    let phone = Device {
        name: String::from("Phone"),
        required_watts: 18,
    };
    let laptop = Device {
        name: String::from("Laptop"),
        required_watts: 65,
    };

    // Clone a device
    let phone_backup = phone.clone();
    println!("\nPhone backup: {:?}", phone_backup);

    // Compare devices by required_watts
    let charger_watts = 65;
    let compatible = vec![phone, laptop]
        .iter()
        .filter(|d| d.required_watts <= charger_watts)
        .collect::<Vec<_>>();
    println!("Compatible devices (<= {}W): {:?}", charger_watts, compatible);
}

输出:

TEXT 📖 仅展示
Debug: ChargerSpec { brand: "Anker", watts: 65, usb_c: true }
Pretty: ChargerSpec {
    brand: "Anker",
    watts: 65,
    usb_c: true,
}
Cloned: ChargerSpec { brand: "Anker", watts: 65, usb_c: true }
Copied (implicit): ChargerSpec { brand: "Anker", watts: 65, usb_c: true }
Original still valid: ChargerSpec { brand: "Anker", watts: 65, usb_c: true }
spec_a == spec_b: true
spec_a == spec_c: false
spec_a != spec_c: true

Phone backup: Device { name: "Phone", required_watts: 18 }
Compatible devices (<= 65W): [Device { name: "Phone", required_watts: 18 }, Device { name: "Laptop", required_watts: 65 }]

#[derive(Debug, Clone, Copy, PartialEq)] 一行代码,Rust 编译器自动为 ChargerSpec 生成了四个 trait 的实现。注意 CopyClone 的区别:Clone 需要显式调用 .clone(),而 Copy 是隐式按位复制(赋值不会 move)。Device 没有 Copy 是因为 String 类型没有实现 Copy(它在堆上分配内存)。


▶ 示例 3:Trait 作为参数——impl Trait 与泛型约束(难度 ⭐⭐)

RUST
// ============================================
// Trait as parameter: impl Trait, generic bounds, where clause
// ============================================

trait USBDevice {
    fn device_name(&self) -> &str;
    fn power_draw(&self) -> u32;
}

struct Mouse;
struct Keyboard;
struct Webcam;

impl USBDevice for Mouse {
    fn device_name(&self) -> &str { "Mouse" }
    fn power_draw(&self) -> u32 { 2 }
}

impl USBDevice for Keyboard {
    fn device_name(&self) -> &str { "Keyboard" }
    fn power_draw(&self) -> u32 { 3 }
}

impl USBDevice for Webcam {
    fn device_name(&self) -> &str { "Webcam" }
    fn power_draw(&self) -> u32 { 5 }
}

// --- Style 1: impl Trait (sugar for simple cases) ---
fn plug_device(device: &impl USBDevice) {
    println!("[Plugged] {} (draws {}W)", device.device_name(), device.power_draw());
}

// --- Style 2: Generic bound T: Trait (explicit type parameter) ---
fn print_device_spec<T: USBDevice>(device: &T) {
    println!("[Spec] {} - Power: {}W", device.device_name(), device.power_draw());
}

// --- Style 3: where clause (best for complex bounds) ---
fn check_compatible<T>(device: &T, max_power: u32) -> bool
where
    T: USBDevice,
{
    device.power_draw() <= max_power
}

// --- Style 4: Multiple trait bounds ---
use std::fmt::Debug;
fn describe_device(device: &(impl USBDevice + Debug)) {
    println!("[Debug] Device: {:?}", device);
}

fn main() {
    let mouse = Mouse;
    let keyboard = Keyboard;
    let webcam = Webcam;

    // impl Trait syntax
    plug_device(&mouse);
    plug_device(&keyboard);

    // Generic bound syntax
    print_device_spec(&webcam);

    // where clause
    println!("\n--- Compatibility Check (max 3W) ---");
    println!("Mouse compatible: {}", check_compatible(&mouse, 3));
    println!("Keyboard compatible: {}", check_compatible(&keyboard, 3));
    println!("Webcam compatible: {}", check_compatible(&webcam, 3));

    // Calculate total power draw for a list
    let devices: Vec<&dyn USBDevice> = vec![&mouse, &keyboard, &webcam];
    let total_power: u32 = devices.iter().map(|d| d.power_draw()).sum();
    println!("\nTotal power draw: {}W / 15W budget", total_power);
}

输出:

TEXT 📖 仅展示
[Plugged] Mouse (draws 2W)
[Plugged] Keyboard (draws 3W)
[Spec] Webcam - Power: 5W

--- Compatibility Check (max 3W) ---
Mouse compatible: true
Keyboard compatible: true
Webcam compatible: false

Total power draw: 10W / 15W budget

四种 trait 参数风格各有适用场景:impl Trait(简洁,适合单一 trait)、T: Trait(明确类型参数名,适合需要引用类型)、where T: Trait(多个约束时可读性最好)、impl Trait + AnotherTrait(多约束。注意 Vec<&dyn USBDevice> 是 trait 对象(见下一例)——这里用于存储不同类型的引用。


▶ 示例 4:Trait 对象 dyn Trait 与 Trait 继承(难度 ⭐⭐⭐)

RUST
// ============================================
// dyn Trait (runtime dispatch) + Trait inheritance
// ============================================

use std::fmt::Debug;

// --- Super trait (trait inheritance) ---
// AnyDevice "inherits" from Debug: to implement AnyDevice,
// a type must also implement Debug
trait AnyDevice: Debug {
    fn model_name(&self) -> &str;
}

// UsbDevice extends AnyDevice: it requires Debug + AnyDevice
trait UsbDevice: AnyDevice {
    fn usb_version(&self) -> &str;
    fn transfer_speed(&self) -> &str;
}

// --- Implement the trait hierarchy ---
#[derive(Debug)]
struct FlashDrive {
    name: String,
    capacity_gb: u32,
}

impl AnyDevice for FlashDrive {
    fn model_name(&self) -> &str {
        &self.name
    }
}

impl UsbDevice for FlashDrive {
    fn usb_version(&self) -> &str {
        "USB 3.2 Gen 2"
    }

    fn transfer_speed(&self) -> &str {
        "10 Gbps"
    }
}

#[derive(Debug)]
struct ExternalSSD {
    name: String,
    capacity_tb: f64,
}

impl AnyDevice for ExternalSSD {
    fn model_name(&self) -> &str {
        &self.name
    }
}

impl UsbDevice for ExternalSSD {
    fn usb_version(&self) -> &str {
        "USB 3.2 Gen 2x2"
    }

    fn transfer_speed(&self) -> &str {
        "20 Gbps"
    }
}

// --- Function using trait objects ---
// Accept a heterogeneous collection of UsbDevice implementors
fn list_devices(devices: &[Box<dyn UsbDevice>]) {
    for (i, device) in devices.iter().enumerate() {
        println!(
            "Device #{}: {} ({} - {}, Debug: {:?})",
            i + 1,
            device.model_name(),
            device.usb_version(),
            device.transfer_speed(),
            device,
        );
    }
}

// --- Function returning a trait object ---
fn make_device(device_type: &str) -> Option<Box<dyn UsbDevice>> {
    match device_type {
        "flash" => Some(Box::new(FlashDrive {
            name: String::from("SanDisk 128GB"),
            capacity_gb: 128,
        })),
        "ssd" => Some(Box::new(ExternalSSD {
            name: String::from("Samsung T7 1TB"),
            capacity_tb: 1.0,
        })),
        _ => None,
    }
}

fn main() {
    // Heterogeneous collection: different types, same trait
    let drive1 = Box::new(FlashDrive {
        name: String::from("Kingston 64GB"),
        capacity_gb: 64,
    });
    let drive2 = Box::new(ExternalSSD {
        name: String::from("WD My Passport 2TB"),
        capacity_tb: 2.0,
    });

    let all_devices: Vec<Box<dyn UsbDevice>> = vec![drive1, drive2];
    println!("--- Connected Devices ---");
    list_devices(&all_devices);

    // Factory function returning trait objects
    println!("\n--- Device Factory ---");
    if let Some(device) = make_device("ssd") {
        println!("Created: {} ({} - {})", device.model_name(), device.usb_version(), device.transfer_speed());
    }

    // Trait inheritance in action: UsbDevice requires Debug
    // so we can use both {:?} and trait methods
    println!("\n--- Debug via Super Trait ---");
    let flash = FlashDrive {
        name: String::from("Lexar 32GB"),
        capacity_gb: 32,
    };
    // flash has Debug (from AnyDevice: Debug), AnyDevice, and UsbDevice
    println!("Debug: {:?}", flash);
    println!("Model: {}", flash.model_name());
    println!("USB: {}", flash.usb_version());
}

输出:

TEXT 📖 仅展示
--- Connected Devices ---
Device #1: Kingston 64GB (USB 3.2 Gen 2 - 10 Gbps, Debug: FlashDrive { name: "Kingston 64GB", capacity_gb: 64 })
Device #2: WD My Passport 2TB (USB 3.2 Gen 2x2 - 20 Gbps, Debug: ExternalSSD { name: "WD My Passport 2TB", capacity_tb: 2.0 })

--- Device Factory ---
Created: Samsung T7 1TB (USB 3.2 Gen 2x2 - 20 Gbps)

--- Debug via Super Trait ---
Debug: FlashDrive { name: "Lexar 32GB", capacity_gb: 32 }
Model: Lexar 32GB
USB: USB 3.2 Gen 2

Trait 继承(超 trait):trait AnyDevice: Debug 意味着"任何实现 AnyDevice 的类型必须也实现 Debug"。trait UsbDevice: AnyDevice 进一步叠加——形成一个三层 trait 层次。实现 UsbDevice 的类型必须同时实现 Debug + AnyDevice + UsbDevice 的所有方法。

Trait 对象 dyn Trait:使用 Box<dyn UsbDevice> 可以在一个集合中存储不同类型实现了同一 trait 的对象。方法调用通过虚表(vtable)在运行时派发——有微小性能开销,但换取极大的灵活性。make_device 函数返回 Option<Box<dyn UsbDevice>> 体现了"工厂模式"。


▶ 示例 5:综合练习——图形面积计算(难度 ⭐⭐⭐)

RUST
// ============================================
// 综合示例:Trait + 泛型约束 + dyn Trait
// ============================================

use std::fmt::Debug;

trait Shape: Debug {
    fn area(&self) -> f64;
    fn name(&self) -> &str;
    fn describe(&self) -> String {
        format!("{}: 面积 = {:.2}", self.name(), self.area())
    }
}

#[derive(Debug)]
struct Circle { radius: f64 }
#[derive(Debug)]
struct Rectangle { width: f64, height: f64 }
#[derive(Debug)]
struct Triangle { base: f64, height: f64 }

impl Shape for Circle {
    fn area(&self) -> f64 { std::f64::consts::PI * self.radius * self.radius }
    fn name(&self) -> &str { "圆形" }
}

impl Shape for Rectangle {
    fn area(&self) -> f64 { self.width * self.height }
    fn name(&self) -> &str { "矩形" }
}

impl Shape for Triangle {
    fn area(&self) -> f64 { 0.5 * self.base * self.height }
    fn name(&self) -> &str { "三角形" }
}

fn total_area(shapes: &[Box<dyn Shape>]) -> f64 {
    shapes.iter().map(|s| s.area()).sum()
}

fn largest<T: Shape>(shapes: &[T]) -> &T {
    shapes.iter().max_by(|a, b| a.area().partial_cmp(&b.area()).unwrap()).unwrap()
}

fn print_all(shapes: &[Box<dyn Shape>]) {
    for s in shapes {
        println!("  {}", s.describe());
    }
}

fn main() {
    let shapes_static: Vec<&dyn Shape> = vec![
        &Circle { radius: 5.0 },
        &Rectangle { width: 4.0, height: 6.0 },
        &Triangle { base: 3.0, height: 8.0 },
    ];

    println!("=== 静态引用遍历 ===");
    for s in &shapes_static {
        println!("  {}", s.describe());
    }

    let shapes_dynamic: Vec<Box<dyn Shape>> = vec![
        Box::new(Circle { radius: 10.0 }),
        Box::new(Rectangle { width: 3.0, height: 7.0 }),
        Box::new(Triangle { base: 6.0, height: 4.0 }),
    ];

    println!("\n=== 动态分发 ===");
    print_all(&shapes_dynamic);
    println!("总面积: {:.2}", total_area(&shapes_dynamic));

    let homogenous = vec![
        Circle { radius: 3.0 },
        Circle { radius: 7.0 },
        Circle { radius: 5.0 },
    ];
    let biggest = largest(&homogenous);
    println!("\n最大圆形: {}", biggest.describe());
}

输出:

TEXT 📖 仅展示
=== 静态引用遍历 ===
  圆形: 面积 = 78.54
  矩形: 面积 = 24.00
  三角形: 面积 = 12.00

=== 动态分发 ===
  圆形: 面积 = 314.16
  矩形: 面积 = 21.00
  三角形: 面积 = 12.00
总面积: 347.16

最大圆形: 圆形: 面积 = 153.94

同一个 Shape trait 被三种方式使用:&dyn Shape 静态引用切片、Box<dyn Shape> 动态分发集合、泛型约束 T: Shape 找最大值。describe 是 trait 的默认方法,所有实现者自动继承。


❓ 常见问题

Q impl Traitdyn Trait 有什么区别?什么时候用哪个?
A impl Trait 是编译时静态分发,dyn Trait 是运行时动态分发。
Q #[derive(Debug)] 和手动实现有什么区别?
A derive 自动生成样板代码,适合字段较少的简单结构体。
Q CopyClone 的区别到底是什么?
A Copy 是隐式按位复制(赋值不转移所有权),Clone 是显式深拷贝(调用 .clone())。
Q trait 继承和面向对象语言中的类继承有什么区别?
A Rust 的 trait 继承是"接口继承"(继承方法签名),不是"实现继承"(继承实现 + 状态)。
Q trait 约束中 T: Trait1 + Trait2where T: Trait1 + Trait2 写法一样吗?
A 语义完全相同,只是语法风格不同。
Q 空 trait(marker trait)有什么用途?
A 标记 trait 没有方法,用于给类型"打标签"以启用某些编译器行为或约束。

📖 小节


📝 作业

  1. 难度 ⭐:定义一个 trait Drawable { fn draw(&self); }。为两个结构体 CircleSquare 实现该 trait,各打印不同的图形。写一个泛型函数 fn render<T: Drawable>(item: &T) 调用 draw。在 main 中分别渲染一个圆形和一个正方形。

  2. 难度 ⭐⭐:定义一个 trait Summary { fn summarize(&self) -> String; fn author(&self) -> &str; },其中 author() 为默认方法,返回 "Anonymous"。为结构体 Article { title: String, content: String }Tweet { username: String, text: String } 实现该 trait。创建两个文章和两条推文,放入 Vec<Box<dyn Summary>> 中遍历打印摘要。

  3. 难度 ⭐⭐⭐:定义一个 trait 层次:trait Vehicle: std::fmt::Debug { fn fuel_type(&self) -> &str; },然后 trait ElectricVehicle: Vehicle { fn battery_capacity_kwh(&self) -> f64; fn range_km(&self) -> f64; }。为结构体 TeslaModel3NissanLeaf 实现 ElectricVehicle。写一个函数 fn print_fleet(vehicles: &[Box<dyn ElectricVehicle>]) 遍历并打印每辆车的信息。在 main 中创建两种车的实例并测试。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏