构想一个场景,咱们定义了很多的构造,然而之前都只是为了贮存一些静态数据,那能不能通过增加一些属性,增加的属性值是一个办法,该办法用于返回一个跟构造自身参数相关联的计算结果呢?
是能够的,废话少说先上示例:
#[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 defaultwarning: 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的命名空间:::语法用于关联函数和模块创立的命名空间。