Skip to content

方法与关联函数

> 学习 impl 块定义方法,理解实例方法(&self)与关联函数(无 self)的区别。

结构体与方法

impl 块基础

rust
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 实例方法(第一个参数是&self)
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // 另一个实例方法
    fn perimeter(&self) -> u32 {
        2 * (self.width + self.height)
    }
}

fn main() {
    let rect = Rectangle {
        width: 30,
        height: 50,
    };

    println!("面积:{}", rect.area());
    println!("周长:{}", rect.perimeter());
    println!("调试输出:{:?}", rect);
}
▶ Run

self 的三种形式

rust
struct Data {
    value: i32,
}

impl Data {
    // &self - 不可变借用(最常用)
    fn print(&self) {
        println!("值:{}", self.value);
    }

    // &mut self - 可变借用
    fn increment(&mut self) {
        self.value += 1;
    }

    // self - 获取所有权(消耗自己)
    fn into_value(self) -> i32 {
        self.value
    }
}

fn main() {
    let mut data = Data { value: 42 };

    data.print();       // 借用,data 仍可用
    data.increment();   // 可变借用,修改值
    let value = data.into_value();  // 移动,data 不再可用

    // data.print();  // ❌ 错误:data 已移动
}
▶ Run

带参数的方法

rust
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // 方法接受另一个结构体实例
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }

    // 可变方法
    fn double_size(&mut self) {
        self.width *= 2;
        self.height *= 2;
    }
}

fn main() {
    let rect1 = Rectangle { width: 100, height: 50 };
    let rect2 = Rectangle { width: 50, height: 30 };

    println!("rect1 能否容纳 rect2: {}", rect1.can_hold(&rect2));

    let mut rect3 = rect2;
    rect3.double_size();
    println!("翻倍后:{:?}", rect3);
}
▶ Run

关联函数(构造函数)

new 函数

rust
#[derive(Debug)]
struct User {
    username: String,
    email: String,
    active: bool,
}

impl User {
    // 关联函数(没有 self 参数)
    fn new(username: String, email: String) -> Self {
        Self {
            username,
            email,
            active: true,
        }
    }

    // 带默认值的构造函数
    fn with_defaults(username: String) -> Self {
        Self {
            username,
            email: String::from("unknown@example.com"),
            active: true,
        }
    }

    fn print_info(&self) {
        println!("用户:{} ({})", self.username, self.email);
    }
}

fn main() {
    let user1 = User::new(
        String::from("alice"),
        String::from("alice@example.com"),
    );

    let user2 = User::with_defaults(String::from("bob"));

    user1.print_info();
    user2.print_info();
}
▶ Run

多个构造函数

rust
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 标准构造函数
    fn new(width: u32, height: u32) -> Self {
        Self { width, height }
    }

    // 正方形
    fn square(size: u32) -> Self {
        Self {
            width: size,
            height: size,
        }
    }

    // 从元组创建
    fn from_tuple((w, h): (u32, u32)) -> Self {
        Self {
            width: w,
            height: h,
        }
    }

    fn area(&self) -> u32 {
        self.width * self.height
    }
}

fn main() {
    let rect1 = Rectangle::new(10, 20);
    let rect2 = Rectangle::square(15);
    let rect3 = Rectangle::from_tuple((5, 10));

    println!("rect1 面积:{}", rect1.area());
    println!("rect2 面积:{}", rect2.area());
    println!("rect3 面积:{}", rect3.area());
}
▶ Run

小结

  • impl Struct { } 定义方法,可以有多个 impl 块
  • 实例方法:&self(只读)、&mut self(可变)、self(消耗)
  • 关联函数:无 self 参数,用于构造函数(如 new
  • 调用:instance.method() 方法,Struct::function() 关联函数

练习题

详见:练习题







---

## 多个 impl 块

```rust
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

// 第一个 impl 块
impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

// 第二个 impl 块
impl Rectangle {
    fn perimeter(&self) -> u32 {
        2 * (self.width + self.height)
    }

    fn is_square(&self) -> bool {
        self.width == self.height
    }
}

// 第三个 impl 块(可以用于条件编译)
#[cfg(debug_assertions)]
impl Rectangle {
    fn debug_print(&self) {
        println!("[DEBUG] Rectangle: {}x{}", self.width, self.height);
    }
}

fn main() {
    let rect = Rectangle { width: 10, height: 20 };

    println!("面积:{}", rect.area());
    println!("周长:{}", rect.perimeter());
    println!("是正方形:{}", rect.is_square());

    #[cfg(debug_assertions)]
    rect.debug_print();
}