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. }

6. // Implementation block, all `Point` methods go in here
7. impl Point {
8. // This is a static method
9. // Static methods don't need to be called by an instance
10. // These methods are generally used as constructors
11. fn origin() -> Point {
12. Point { x: 0.0, y: 0.0 }
13. }

15. // Another static method, taking two arguments:
16. fn new(x: f64, y: f64) -> Point {
17. Point { x: x, y: y }
18. }
19. }

21. struct Rectangle {
22. p1: Point,
23. p2: Point,
24. }

26. impl Rectangle {
27. // This is an instance method
28. // `&self` is sugar for `self: &Self`, where `Self` is the type of the
29. // caller object. In this case `Self` = `Rectangle`
30. fn area(&self) -> f64 {
31. // `self` gives access to the struct fields via the dot operator
32. let Point { x: x1, y: y1 } = self.p1;
33. let Point { x: x2, y: y2 } = self.p2;

35. // `abs` is a `f64` method that returns the absolute value of the
36. // caller
37. ((x1 - x2) * (y1 - y2)).abs()
38. }

40. fn perimeter(&self) -> f64 {
41. let Point { x: x1, y: y1 } = self.p1;
42. let Point { x: x2, y: y2 } = self.p2;

44. 2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
45. }

47. // This method requires the caller object to be mutable
48. // `&mut self` desugars to `self: &mut Self`
49. fn translate(&mut self, x: f64, y: f64) {
50. self.p1.x += x;
51. self.p2.x += x;

53. self.p1.y += y;
54. self.p2.y += y;
55. }
56. }

58. // `Pair` owns resources: two heap allocated integers
59. struct Pair(Box<i32>, Box<i32>);

61. impl Pair {
62. // This method "consumes" the resources of the caller object
63. // `self` desugars to `self: Self`
64. fn destroy(self) {
65. // Destructure `self`
66. let Pair(first, second) = self;

68. println!("Destroying Pair({}, {})", first, second);

70. // `first` and `second` go out of scope and get freed
71. }
72. }

74. fn main() {
75. let rectangle = Rectangle {
76. // Static methods are called using double colons
77. p1: Point::origin(),
78. p2: Point::new(3.0, 4.0),
79. };

81. // Instance methods are called using the dot operator
82. // Note that the first argument `&self` is implicitly passed, i.e.
83. // `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)`
84. println!("Rectangle perimeter: {}", rectangle.perimeter());
85. println!("Rectangle area: {}", rectangle.area());

87. let mut square = Rectangle {
88. p1: Point::origin(),
89. p2: Point::new(1.0, 1.0),
90. };

92. // Error! `rectangle` is immutable, but this method requires a mutable
93. // object
94. //rectangle.translate(1.0, 0.0);
95. // TODO ^ Try uncommenting this line

97. // Okay! Mutable objects can call mutable methods
98. square.translate(1.0, 1.0);

100. let pair = Pair(Box::new(1), Box::new(2));

102. pair.destroy();

104. // Error! Previous `destroy` call "consumed" `pair`
105. //pair.destroy();
106. // TODO ^ Try uncommenting this line
107. }