]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
1 | # Method-call expressions |
2 | ||
0bf4aa26 XL |
3 | > **<sup>Syntax</sup>**\ |
4 | > _MethodCallExpression_ :\ | |
5 | > [_Expression_] `.` [_PathExprSegment_] `(`[_CallParams_]<sup>?</sup> `)` | |
6 | ||
6a06907d XL |
7 | A _method call_ consists of an expression (the *receiver*) followed by a single dot, an expression path segment, and a parenthesized expression-list. |
8 | Method calls are resolved to associated [methods] on specific traits, either statically dispatching to a method if the exact `self`-type of the left-hand-side is known, or dynamically dispatching if the left-hand-side expression is an indirect [trait object](../types/trait-object.md). | |
ea8adc8c XL |
9 | |
10 | ```rust | |
11 | let pi: Result<f32, _> = "3.14".parse(); | |
12 | let log_pi = pi.unwrap_or(1.0).log(2.72); | |
13 | # assert!(1.14 < log_pi && log_pi < 1.15) | |
14 | ``` | |
15 | ||
6a06907d XL |
16 | When looking up a method call, the receiver may be automatically dereferenced or borrowed in order to call a method. |
17 | This requires a more complex lookup process than for other functions, since there may be a number of possible methods to call. | |
18 | The following procedure is used: | |
2c00a5a8 | 19 | |
6a06907d XL |
20 | The first step is to build a list of candidate receiver types. |
21 | Obtain these by repeatedly [dereferencing][dereference] the receiver expression's type, adding each type encountered to the list, then finally attempting an [unsized coercion] at the end, and adding the result type if that is successful. | |
22 | Then, for each candidate `T`, add `&T` and `&mut T` to the list immediately after `T`. | |
2c00a5a8 | 23 | |
6a06907d | 24 | For instance, if the receiver has type `Box<[i32;2]>`, then the candidate types will be `Box<[i32;2]>`, `&Box<[i32;2]>`, `&mut Box<[i32;2]>`, `[i32; 2]` (by dereferencing), `&[i32; 2]`, `&mut [i32; 2]`, `[i32]` (by unsized coercion), `&[i32]`, and finally `&mut [i32]`. |
2c00a5a8 | 25 | |
6a06907d | 26 | Then, for each candidate type `T`, search for a [visible] method with a receiver of that type in the following places: |
ea8adc8c | 27 | |
2c00a5a8 | 28 | 1. `T`'s inherent methods (methods implemented directly on `T`). |
6a06907d XL |
29 | 1. Any of the methods provided by a [visible] trait implemented by `T`. |
30 | If `T` is a type parameter, methods provided by trait bounds on `T` are looked up first. | |
31 | Then all remaining methods in scope are looked up. | |
32 | ||
33 | > Note: the lookup is done for each type in order, which can occasionally lead to surprising results. | |
34 | > The below code will print "In trait impl!", because `&self` methods are looked up first, the trait method is found before the struct's `&mut self` method is found. | |
2c00a5a8 XL |
35 | > |
36 | > ```rust | |
37 | > struct Foo {} | |
38 | > | |
39 | > trait Bar { | |
40 | > fn bar(&self); | |
41 | > } | |
42 | > | |
43 | > impl Foo { | |
44 | > fn bar(&mut self) { | |
45 | > println!("In struct impl!") | |
46 | > } | |
47 | > } | |
48 | > | |
49 | > impl Bar for Foo { | |
50 | > fn bar(&self) { | |
51 | > println!("In trait impl!") | |
52 | > } | |
53 | > } | |
54 | > | |
55 | > fn main() { | |
56 | > let mut f = Foo{}; | |
57 | > f.bar(); | |
58 | > } | |
59 | > ``` | |
60 | ||
6a06907d | 61 | If this results in multiple possible candidates, then it is an error, and the receiver must be [converted][disambiguate call] to an appropriate receiver type to make the method call. |
2c00a5a8 | 62 | |
6a06907d XL |
63 | This process does not take into account the mutability or lifetime of the receiver, or whether a method is `unsafe`. |
64 | Once a method is looked up, if it can't be called for one (or more) of those reasons, the result is a compiler error. | |
2c00a5a8 | 65 | |
6a06907d XL |
66 | If a step is reached where there is more than one possible method, such as where generic methods or traits are considered the same, then it is a compiler error. |
67 | These cases require a [disambiguating function call syntax] for method and function invocation. | |
ff7c6d11 | 68 | |
8faf50e0 XL |
69 | <div class="warning"> |
70 | ||
6a06907d XL |
71 | ***Warning:*** For [trait objects], if there is an inherent method of the same name as a trait method, it will give a compiler error when trying to call the method in a method call expression. |
72 | Instead, you can call the method using [disambiguating function call syntax], in which case it calls the trait method, not the inherent method. | |
73 | There is no way to call the inherent method. | |
74 | Just don't define inherent methods on trait objects with the same name a trait method and you'll be fine. | |
8faf50e0 XL |
75 | |
76 | </div> | |
2c00a5a8 | 77 | |
416331ca XL |
78 | [_CallParams_]: call-expr.md |
79 | [_Expression_]: ../expressions.md | |
80 | [_PathExprSegment_]: ../paths.md#paths-in-expressions | |
81 | [visible]: ../visibility-and-privacy.md | |
82 | [trait objects]: ../types/trait-object.md | |
83 | [disambiguate call]: call-expr.md#disambiguating-function-calls | |
84 | [disambiguating function call syntax]: call-expr.md#disambiguating-function-calls | |
85 | [dereference]: operator-expr.md#the-dereference-operator | |
86 | [methods]: ../items/associated-items.md#methods | |
87 | [unsized coercion]: ../type-coercions.md#unsized-coercions |