Methods

Methods are functions attached to objects. These methods have access to the
data of the object and its other methods via the self keyword. Methods are
defined under an impl block.

  1. struct Point {
  2. x: f64,
  3. y: f64,
  4. }
  5. // Implementation block, all `Point` methods go in here
  6. impl Point {
  7. // This is a static method
  8. // Static methods don't need to be called by an instance
  9. // These methods are generally used as constructors
  10. fn origin() -> Point {
  11. Point { x: 0.0, y: 0.0 }
  12. }
  13. // Another static method, taking two arguments:
  14. fn new(x: f64, y: f64) -> Point {
  15. Point { x: x, y: y }
  16. }
  17. }
  18. struct Rectangle {
  19. p1: Point,
  20. p2: Point,
  21. }
  22. impl Rectangle {
  23. // This is an instance method
  24. // `&self` is sugar for `self: &Self`, where `Self` is the type of the
  25. // caller object. In this case `Self` = `Rectangle`
  26. fn area(&self) -> f64 {
  27. // `self` gives access to the struct fields via the dot operator
  28. let Point { x: x1, y: y1 } = self.p1;
  29. let Point { x: x2, y: y2 } = self.p2;
  30. // `abs` is a `f64` method that returns the absolute value of the
  31. // caller
  32. ((x1 - x2) * (y1 - y2)).abs()
  33. }
  34. fn perimeter(&self) -> f64 {
  35. let Point { x: x1, y: y1 } = self.p1;
  36. let Point { x: x2, y: y2 } = self.p2;
  37. 2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
  38. }
  39. // This method requires the caller object to be mutable
  40. // `&mut self` desugars to `self: &mut Self`
  41. fn translate(&mut self, x: f64, y: f64) {
  42. self.p1.x += x;
  43. self.p2.x += x;
  44. self.p1.y += y;
  45. self.p2.y += y;
  46. }
  47. }
  48. // `Pair` owns resources: two heap allocated integers
  49. struct Pair(Box<i32>, Box<i32>);
  50. impl Pair {
  51. // This method "consumes" the resources of the caller object
  52. // `self` desugars to `self: Self`
  53. fn destroy(self) {
  54. // Destructure `self`
  55. let Pair(first, second) = self;
  56. println!("Destroying Pair({}, {})", first, second);
  57. // `first` and `second` go out of scope and get freed
  58. }
  59. }
  60. fn main() {
  61. let rectangle = Rectangle {
  62. // Static methods are called using double colons
  63. p1: Point::origin(),
  64. p2: Point::new(3.0, 4.0),
  65. };
  66. // Instance methods are called using the dot operator
  67. // Note that the first argument `&self` is implicitly passed, i.e.
  68. // `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)`
  69. println!("Rectangle perimeter: {}", rectangle.perimeter());
  70. println!("Rectangle area: {}", rectangle.area());
  71. let mut square = Rectangle {
  72. p1: Point::origin(),
  73. p2: Point::new(1.0, 1.0),
  74. };
  75. // Error! `rectangle` is immutable, but this method requires a mutable
  76. // object
  77. //rectangle.translate(1.0, 0.0);
  78. // TODO ^ Try uncommenting this line
  79. // Okay! Mutable objects can call mutable methods
  80. square.translate(1.0, 1.0);
  81. let pair = Pair(Box::new(1), Box::new(2));
  82. pair.destroy();
  83. // Error! Previous `destroy` call "consumed" `pair`
  84. //pair.destroy();
  85. // TODO ^ Try uncommenting this line
  86. }