共计 2663 个字符,预计需要花费 7 分钟才能阅读完成。
构想一个场景,咱们定义了很多的构造,然而之前都只是为了贮存一些静态数据,那能不能通过增加一些属性,增加的属性值是一个办法,该办法用于返回一个跟构造自身参数相关联的计算结果呢?
是能够的,废话少说先上示例:
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {fn get_perimeter(&self) -> u32 {(self.width + self.height) * 2
}
}
fn main() {
let rect1 = Rectangle {
width: 36,
height: 18,
};
println!("矩形:{:?} 的矩形的周长为:{}", rect1, rect1.get_perimeter())
}
cargo run
矩形:Rectangle {width: 36, height: 18} 的矩形的周长为:108
为了在 Rectangle 的上下文中定义函数,咱们启动一个 impl(实现)块。而后,咱们将区域函数挪动到 impl 大括号内,并将第一个(在这种状况下,仅此参数)参数更改为签名中和注释中各处的 self。在 main 中,咱们调用了 get_perimeter 函数并传递了 rect1 作为参数,咱们能够改用办法语法在 Rectangle 实例上调用 get_perimeter 办法。办法语法在实例之后:咱们在办法名称,括号和任何参数前面增加一个点。
在区域签名中,咱们应用 &self 而不是矩形:&Rectangle,因为 Rust 晓得 self 的类型为 Rectangle,因为该办法位于 impl Rectangle 上下文中。请留神,就像在 &Rectangle 中一样,咱们仍须要在 self 之前应用 &。办法能够获得自我的所有权,像咱们在这里所做的那样,不可变地借用自我,或者其自身是可变的去借用自我,就像它们能够应用任何其余参数一样。
咱们在此处抉择 &self 的起因与在函数版本中应用 &Rectangle 的起因雷同:咱们不想取得所有权,咱们只想读取构造中的数据,而不是对其进行写入。如果要在办法执行的过程中更改调用办法的实例,则能够应用 &mut self 作为第一个参数。很少有一种办法只应用 self 作为第一个参数来获取实例的所有权;该办法通常在办法将本身转换为其余模式并且要避免调用者在转换后应用原始实例时应用。
除了应用办法语法而且不用在每个办法的签名中重复使用 self 的类型之外,应用办法代替函数的次要益处是对程序结构而言。咱们将类型实例的所有性能都放在一个 impl 块中,而不是让咱们的代码的将来用户在咱们提供的库中的各个地位搜寻 Rectangle 的性能。
一个 struct 能够有多个 impl
有很多参数状况的办法
让咱们通过在 Rectangle 构造上实现第二种办法来练习应用办法。这次,咱们心愿 Rectangle 的一个实例承受 Rectangle 的另一个实例,如果第二个 Rectangle 能够齐全适宜本身 (宽度是长度的 2 倍),则返回 true。否则应返回 false。也就是说,一旦定义了 can_hold 办法,咱们心愿可能编写上面示例所代表的程序:
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {fn get_perimeter(&self) -> u32 {(self.width + self.height) * 2
}
}
impl Rectangle {fn can_hold(&self, other: &Rectangle) -> bool {self.width > other.width && self.height > other.height}
}
fn main() {
let rect1 = Rectangle {
width: 36,
height: 18,
};
let rect2 = Rectangle {
width: 100,
height: 18,
};
let rect3 = Rectangle {
width: 12,
height: 6,
};
println!("矩形 rect1:{:?} 能够包容矩形 rect2:{:?} 吗?{}", rect1, rect2, rect1.can_hold(&rect2));
println!("矩形 rect1:{:?} 能够包容矩形 rect3:{:?} 吗?{}", rect1, rect3, rect1.can_hold(&rect3));
}
cargo run
|
8 | fn get_perimeter(&self) -> u32 {
| ^^^^^^^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: 1 warning emitted
Finished dev [unoptimized + debuginfo] target(s) in 0.53s
Running `target\debug\cargo_learn.exe`
矩形 rect1:Rectangle {width: 36, height: 18} 能够包容矩形 rect2:Rectangle {width: 100, height: 18} 吗?false
矩形 rect1:Rectangle {width: 36, height: 18} 能够包容矩形 rect3:Rectangle {width: 12, height: 6} 吗?true
相干性能
impl 块的另一个有用性能是容许咱们在不以 self 为参数的 impl 块中定义函数。这些之所以称为关联函数,是因为它们与 struct 相关联。它们依然是函数,而不是办法,因为它们没有可应用的构造实例。再次之前咱们曾经应用了 String::from 关联函数。
关联函数通常用于将返回该构造的新实例的构造函数。例如,咱们能够提供一个关联的函数,该函数将具备一个维度参数并将其用作宽度和高度,从而使创立正方形矩形变得更加容易,而不用两次指定雷同的值:
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {fn square(size: u32) -> Rectangle {
Rectangle {
width: size,
height: size,
}
}
}
fn main() {let sq = Rectangle::square(3);
}
要调用此关联函数,咱们将:: 语法与构造名称一起应用;let sq = Rectangle::square(3); 是一个实例。该函数借由 struct 的命名空间::: 语法用于关联函数和模块创立的命名空间。