19·面向对象入门

方法 impl

方法 impl

学习目标

  1. 掌握 impl 块定义方法
  2. 理解 &self&mut selfself 的区别
  3. 掌握关联函数
  4. 理解多个 impl

核心概念

基本方法

struct Circle {
    radius: f64,
}

impl Circle {
    // &self: 不可变借用
    fn area(&self) -> f64 {
        std::f64::consts::PI * self.radius * self.radius
    }

    fn circumference(&self) -> f64 {
        2.0 * std::f64::consts::PI * self.radius
    }

    // &mut self: 可变借用
    fn scale(&mut self, factor: f64) {
        self.radius *= factor;
    }

    // self: 消耗实例
    fn into_square(self) -> f64 {
        self.radius * self.radius
    }
}

fn main() {
    let mut c = Circle { radius: 5.0 };
    println!("面积: {:.2}", c.area());
    println!("周长: {:.2}", c.circumference());

    c.scale(2.0);
    println!("放大后面积: {:.2}", c.area());
}

self 的三种形式

形式含义使用场景
&self不可变借用只读访问
&mut self可变借用需要修改
self获取所有权转换或消耗

关联函数

struct Rectangle {
    width: f64,
    height: f64,
}

impl Rectangle {
    // 关联函数(没有 self)
    fn new(width: f64, height: f64) -> Self {
        Rectangle { width, height }
    }

    fn square(size: f64) -> Self {
        Rectangle { width: size, height: size }
    }

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

fn main() {
    let r = Rectangle::new(10.0, 5.0);
    let s = Rectangle::square(7.0);
    println!("矩形面积: {}", r.area());
    println!("正方形面积: {}", s.area());
}

多个 impl 块

struct Player {
    name: String,
    health: i32,
    attack: i32,
}

impl Player {
    fn new(name: &str) -> Self {
        Player {
            name: String::from(name),
            health: 100,
            attack: 10,
        }
    }
}

impl Player {
    fn is_alive(&self) -> bool {
        self.health > 0
    }

    fn take_damage(&mut self, damage: i32) {
        self.health -= damage;
        if self.health < 0 {
            self.health = 0;
        }
    }

    fn attack(&self, target: &mut Player) {
        target.take_damage(self.attack);
    }
}

fn main() {
    let mut p1 = Player::new("Alice");
    let mut p2 = Player::new("Bob");

    p1.attack(&mut p2);
    println!("{} 生命值: {}", p2.name, p2.health);
}

Builder 模式

struct Server {
    host: String,
    port: u16,
    max_connections: usize,
}

struct ServerBuilder {
    host: String,
    port: u16,
    max_connections: usize,
}

impl ServerBuilder {
    fn new() -> Self {
        ServerBuilder {
            host: String::from("localhost"),
            port: 8080,
            max_connections: 100,
        }
    }

    fn host(mut self, host: &str) -> Self {
        self.host = String::from(host);
        self
    }

    fn port(mut self, port: u16) -> Self {
        self.port = port;
        self
    }

    fn max_connections(mut self, max: usize) -> Self {
        self.max_connections = max;
        self
    }

    fn build(self) -> Server {
        Server {
            host: self.host,
            port: self.port,
            max_connections: self.max_connections,
        }
    }
}

fn main() {
    let server = ServerBuilder::new()
        .host("0.0.0.0")
        .port(3000)
        .max_connections(1000)
        .build();

    println!("{}:{}", server.host, server.port);
}

实践练习

练习 1:栈实现

struct Stack<T> {
    elements: Vec<T>,
}

impl<T> Stack<T> {
    fn new() -> Self {
        Stack { elements: Vec::new() }
    }

    fn push(&mut self, item: T) {
        self.elements.push(item);
    }

    fn pop(&mut self) -> Option<T> {
        self.elements.pop()
    }

    fn peek(&self) -> Option<&T> {
        self.elements.last()
    }

    fn is_empty(&self) -> bool {
        self.elements.is_empty()
    }

    fn size(&self) -> usize {
        self.elements.len()
    }
}

fn main() {
    let mut stack = Stack::new();
    stack.push(1);
    stack.push(2);
    stack.push(3);

    println!("栈顶: {:?}", stack.peek());
    println!("弹出: {:?}", stack.pop());
    println!("大小: {}", stack.size());
}

练习 2:链表

enum List<T> {
    Cons(T, Box<List<T>>),
    Nil,
}

impl<T> List<T> {
    fn new() -> Self {
        List::Nil
    }

    fn push(self, value: T) -> Self {
        List::Cons(value, Box::new(self))
    }

    fn len(&self) -> usize {
        match self {
            List::Cons(_, next) => 1 + next.len(),
            List::Nil => 0,
        }
    }

    fn to_vec(&self) -> Vec<&T> where T: std::fmt::Debug {
        let mut result = Vec::new();
        let mut current = self;
        while let List::Cons(val, next) = current {
            result.push(val);
            current = next;
        }
        result
    }
}

fn main() {
    let list = List::new().push(1).push(2).push(3);
    println!("长度: {}", list.len());
    println!("内容: {:?}", list.to_vec());
}

常见错误

1. 忘记 self

struct Foo;
impl Foo {
    fn bar() { }  // 关联函数,不是方法
    // foo.bar();  // ❌ 不能用点调用
    // Foo::bar(); // ✅
}

2. 可变性

struct Counter { count: i32 }
impl Counter {
    fn increment(&mut self) { self.count += 1; }
}
let c = Counter { count: 0 };
// c.increment();  // ❌ c 不是 mut

小结

语法用途
impl Struct { }定义方法
&self不可变借用
&mut self可变借用
self获取所有权
Struct::func()调用关联函数
instance.method()调用方法

练习编辑器

rust
Loading...