方法 impl
学习目标
- 掌握
impl 块定义方法
- 理解
&self、&mut self、self 的区别
- 掌握关联函数
- 理解多个
impl 块
核心概念
基本方法
struct Circle {
radius: f64,
}
impl Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
fn circumference(&self) -> f64 {
2.0 * std::f64::consts::PI * self.radius
}
fn scale(&mut self, factor: f64) {
self.radius *= factor;
}
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 {
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() { }
}
2. 可变性
struct Counter { count: i32 }
impl Counter {
fn increment(&mut self) { self.count += 1; }
}
let c = Counter { count: 0 };
小结
| 语法 | 用途 |
|---|
impl Struct { } | 定义方法 |
&self | 不可变借用 |
&mut self | 可变借用 |
self | 获取所有权 |
Struct::func() | 调用关联函数 |
instance.method() | 调用方法 |