]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
1 | # Operator expressions |
2 | ||
8faf50e0 XL |
3 | > **<sup>Syntax</sup>**\ |
4 | > _OperatorExpression_ :\ | |
5 | > [_BorrowExpression_]\ | |
6 | > | [_DereferenceExpression_]\ | |
7 | > | [_ErrorPropagationExpression_]\ | |
8 | > | [_NegationExpression_]\ | |
9 | > | [_ArithmeticOrLogicalExpression_]\ | |
10 | > | [_ComparisonExpression_]\ | |
11 | > | [_LazyBooleanExpression_]\ | |
12 | > | [_TypeCastExpression_]\ | |
13 | > | [_AssignmentExpression_]\ | |
14 | > | [_CompoundAssignmentExpression_] | |
0531ce1d | 15 | |
6a06907d XL |
16 | Operators are defined for built in types by the Rust language. |
17 | Many of the following operators can also be overloaded using traits in `std::ops` or `std::cmp`. | |
ea8adc8c XL |
18 | |
19 | ## Overflow | |
20 | ||
21 | Integer operators will panic when they overflow when compiled in debug mode. | |
6a06907d XL |
22 | The `-C debug-assertions` and `-C overflow-checks` compiler flags can be used to control this more directly. |
23 | The following things are considered to be overflow: | |
24 | ||
25 | * When `+`, `*` or `-` create a value greater than the maximum value, or less than the minimum value that can be stored. | |
26 | This includes unary `-` on the smallest value of any signed integer type. | |
27 | * Using `/` or `%`, where the left-hand argument is the smallest integer of a signed integer type and the right-hand argument is `-1`. | |
28 | * Using `<<` or `>>` where the right-hand argument is greater than or equal to the number of bits in the type of the left-hand argument, or is negative. | |
ea8adc8c | 29 | |
ea8adc8c XL |
30 | ## Borrow operators |
31 | ||
8faf50e0 XL |
32 | > **<sup>Syntax</sup>**\ |
33 | > _BorrowExpression_ :\ | |
34 | > (`&`|`&&`) [_Expression_]\ | |
35 | > | (`&`|`&&`) `mut` [_Expression_] | |
0531ce1d | 36 | |
6a06907d XL |
37 | The `&` (shared borrow) and `&mut` (mutable borrow) operators are unary prefix operators. |
38 | When applied to a [place expression], this expressions produces a reference (pointer) to the location that the value refers to. | |
39 | The memory location is also placed into a borrowed state for the duration of the reference. | |
40 | For a shared borrow (`&`), this implies that the place may not be mutated, but it may be read or shared again. | |
41 | For a mutable borrow (`&mut`), the place may not be accessed in any way until the borrow expires. | |
42 | `&mut` evaluates its operand in a mutable place expression context. | |
43 | If the `&` or `&mut` operators are applied to a [value expression], then a [temporary value] is created. | |
ff7c6d11 XL |
44 | |
45 | These operators cannot be overloaded. | |
ea8adc8c XL |
46 | |
47 | ```rust | |
48 | { | |
49 | // a temporary with value 7 is created that lasts for this scope. | |
50 | let shared_reference = &7; | |
51 | } | |
52 | let mut array = [-2, 3, 9]; | |
53 | { | |
54 | // Mutably borrows `array` for this scope. | |
55 | // `array` may only be used through `mutable_reference`. | |
56 | let mutable_reference = &mut array; | |
57 | } | |
58 | ``` | |
59 | ||
6a06907d | 60 | Even though `&&` is a single token ([the lazy 'and' operator](#lazy-boolean-operators)), when used in the context of borrow expressions it works as two borrows: |
0531ce1d XL |
61 | |
62 | ```rust | |
63 | // same meanings: | |
64 | let a = && 10; | |
65 | let a = & & 10; | |
66 | ||
67 | // same meanings: | |
68 | let a = &&&& mut 10; | |
69 | let a = && && mut 10; | |
70 | let a = & & & & mut 10; | |
71 | ``` | |
72 | ||
ea8adc8c XL |
73 | ## The dereference operator |
74 | ||
8faf50e0 XL |
75 | > **<sup>Syntax</sup>**\ |
76 | > _DereferenceExpression_ :\ | |
0531ce1d XL |
77 | > `*` [_Expression_] |
78 | ||
6a06907d XL |
79 | The `*` (dereference) operator is also a unary prefix operator. |
80 | When applied to a [pointer](../types/pointer.md) it denotes the pointed-to location. | |
81 | If the expression is of type `&mut T` or `*mut T`, and is either a local variable, a (nested) field of a local variable or is a mutable [place expression], then the resulting memory location can be assigned to. | |
ff7c6d11 | 82 | Dereferencing a raw pointer requires `unsafe`. |
ea8adc8c | 83 | |
6a06907d | 84 | On non-pointer types `*x` is equivalent to `*std::ops::Deref::deref(&x)` in an [immutable place expression context](../expressions.md#mutability) and `*std::ops::DerefMut::deref_mut(&mut x)` in a mutable place expression context. |
ea8adc8c XL |
85 | |
86 | ```rust | |
87 | let x = &7; | |
88 | assert_eq!(*x, 7); | |
89 | let y = &mut 9; | |
90 | *y = 11; | |
91 | assert_eq!(*y, 11); | |
92 | ``` | |
93 | ||
ff7c6d11 XL |
94 | ## The question mark operator |
95 | ||
8faf50e0 XL |
96 | > **<sup>Syntax</sup>**\ |
97 | > _ErrorPropagationExpression_ :\ | |
98 | > [_Expression_] `?` | |
0531ce1d | 99 | |
6a06907d XL |
100 | The question mark operator (`?`) unwraps valid values or returns erroneous values, propagating them to the calling function. |
101 | It is a unary postfix operator that can only be applied to the types `Result<T, E>` and `Option<T>`. | |
ea8adc8c | 102 | |
6a06907d XL |
103 | When applied to values of the `Result<T, E>` type, it propagates errors. |
104 | If the value is `Err(e)`, then it will return `Err(From::from(e))` from the enclosing function or closure. | |
105 | If applied to `Ok(x)`, then it will unwrap the value to evaluate to `x`. | |
ea8adc8c XL |
106 | |
107 | ```rust | |
108 | # use std::num::ParseIntError; | |
109 | fn try_to_parse() -> Result<i32, ParseIntError> { | |
110 | let x: i32 = "123".parse()?; // x = 123 | |
111 | let y: i32 = "24a".parse()?; // returns an Err() immediately | |
112 | Ok(x + y) // Doesn't run. | |
113 | } | |
114 | ||
115 | let res = try_to_parse(); | |
116 | println!("{:?}", res); | |
117 | # assert!(res.is_err()) | |
118 | ``` | |
119 | ||
6a06907d XL |
120 | When applied to values of the `Option<T>` type, it propagates `None`s. |
121 | If the value is `None`, then it will return `None`. | |
122 | If applied to `Some(x)`, then it will unwrap the value to evaluate to `x`. | |
ff7c6d11 XL |
123 | |
124 | ```rust | |
125 | fn try_option_some() -> Option<u8> { | |
126 | let val = Some(1)?; | |
127 | Some(val) | |
128 | } | |
129 | assert_eq!(try_option_some(), Some(1)); | |
130 | ||
131 | fn try_option_none() -> Option<u8> { | |
132 | let val = None?; | |
133 | Some(val) | |
134 | } | |
135 | assert_eq!(try_option_none(), None); | |
136 | ``` | |
137 | ||
138 | `?` cannot be overloaded. | |
139 | ||
ea8adc8c XL |
140 | ## Negation operators |
141 | ||
8faf50e0 XL |
142 | > **<sup>Syntax</sup>**\ |
143 | > _NegationExpression_ :\ | |
144 | > `-` [_Expression_]\ | |
145 | > | `!` [_Expression_] | |
0531ce1d | 146 | |
6a06907d XL |
147 | These are the last two unary operators. |
148 | This table summarizes the behavior of them on primitive types and which traits are used to overload these operators for other types. | |
149 | Remember that signed integers are always represented using two's complement. | |
150 | The operands of all of these operators are evaluated in [value expression context][value expression] so are moved or copied. | |
ea8adc8c | 151 | |
6a06907d XL |
152 | | Symbol | Integer | `bool` | Floating Point | Overloading Trait | |
153 | |--------|-------------|-------------- |----------------|--------------------| | |
154 | | `-` | Negation* | | Negation | `std::ops::Neg` | | |
155 | | `!` | Bitwise NOT | [Logical NOT] | | `std::ops::Not` | | |
ea8adc8c XL |
156 | |
157 | \* Only for signed integer types. | |
158 | ||
159 | Here are some example of these operators | |
160 | ||
161 | ```rust | |
162 | let x = 6; | |
163 | assert_eq!(-x, -6); | |
164 | assert_eq!(!x, -7); | |
165 | assert_eq!(true, !false); | |
166 | ``` | |
167 | ||
168 | ## Arithmetic and Logical Binary Operators | |
169 | ||
8faf50e0 XL |
170 | > **<sup>Syntax</sup>**\ |
171 | > _ArithmeticOrLogicalExpression_ :\ | |
172 | > [_Expression_] `+` [_Expression_]\ | |
173 | > | [_Expression_] `-` [_Expression_]\ | |
174 | > | [_Expression_] `*` [_Expression_]\ | |
175 | > | [_Expression_] `/` [_Expression_]\ | |
176 | > | [_Expression_] `%` [_Expression_]\ | |
177 | > | [_Expression_] `&` [_Expression_]\ | |
178 | > | [_Expression_] `|` [_Expression_]\ | |
179 | > | [_Expression_] `^` [_Expression_]\ | |
180 | > | [_Expression_] `<<` [_Expression_]\ | |
181 | > | [_Expression_] `>>` [_Expression_] | |
0531ce1d | 182 | |
6a06907d XL |
183 | Binary operators expressions are all written with infix notation. |
184 | This table summarizes the behavior of arithmetic and logical binary operators on primitive types and which traits are used to overload these operators for other types. | |
185 | Remember that signed integers are always represented using two's complement. | |
186 | The operands of all of these operators are evaluated in [value expression context][value expression] so are moved or copied. | |
187 | ||
188 | | Symbol | Integer | `bool` | Floating Point | Overloading Trait | Overloading Compound Assignment Trait | | |
189 | |--------|-------------------------|---------------|----------------|--------------------| ------------------------------------- | | |
190 | | `+` | Addition | | Addition | `std::ops::Add` | `std::ops::AddAssign` | | |
191 | | `-` | Subtraction | | Subtraction | `std::ops::Sub` | `std::ops::SubAssign` | | |
192 | | `*` | Multiplication | | Multiplication | `std::ops::Mul` | `std::ops::MulAssign` | | |
193 | | `/` | Division* | | Division | `std::ops::Div` | `std::ops::DivAssign` | | |
194 | | `%` | Remainder | | Remainder | `std::ops::Rem` | `std::ops::RemAssign` | | |
195 | | `&` | Bitwise AND | [Logical AND] | | `std::ops::BitAnd` | `std::ops::BitAndAssign` | | |
196 | | <code>|</code> | Bitwise OR | [Logical OR] | | `std::ops::BitOr` | `std::ops::BitOrAssign` | | |
197 | | `^` | Bitwise XOR | [Logical XOR] | | `std::ops::BitXor` | `std::ops::BitXorAssign` | | |
198 | | `<<` | Left Shift | | | `std::ops::Shl` | `std::ops::ShlAssign` | | |
199 | | `>>` | Right Shift** | | | `std::ops::Shr` | `std::ops::ShrAssign` | | |
ea8adc8c | 200 | |
94b46f34 XL |
201 | \* Integer division rounds towards zero. |
202 | ||
203 | \*\* Arithmetic right shift on signed integer types, logical right shift on | |
ea8adc8c XL |
204 | unsigned integer types. |
205 | ||
206 | Here are examples of these operators being used. | |
207 | ||
208 | ```rust | |
209 | assert_eq!(3 + 6, 9); | |
210 | assert_eq!(5.5 - 1.25, 4.25); | |
211 | assert_eq!(-5 * 14, -70); | |
212 | assert_eq!(14 / 3, 4); | |
213 | assert_eq!(100 % 7, 2); | |
214 | assert_eq!(0b1010 & 0b1100, 0b1000); | |
215 | assert_eq!(0b1010 | 0b1100, 0b1110); | |
216 | assert_eq!(0b1010 ^ 0b1100, 0b110); | |
217 | assert_eq!(13 << 3, 104); | |
218 | assert_eq!(-10 >> 2, -3); | |
219 | ``` | |
220 | ||
221 | ## Comparison Operators | |
222 | ||
8faf50e0 XL |
223 | > **<sup>Syntax</sup>**\ |
224 | > _ComparisonExpression_ :\ | |
225 | > [_Expression_] `==` [_Expression_]\ | |
226 | > | [_Expression_] `!=` [_Expression_]\ | |
227 | > | [_Expression_] `>` [_Expression_]\ | |
228 | > | [_Expression_] `<` [_Expression_]\ | |
229 | > | [_Expression_] `>=` [_Expression_]\ | |
230 | > | [_Expression_] `<=` [_Expression_] | |
0531ce1d | 231 | |
6a06907d XL |
232 | Comparison operators are also defined both for primitive types and many types in the standard library. |
233 | Parentheses are required when chaining comparison operators. For example, the expression `a == b == c` is invalid and may be written as `(a == b) == c`. | |
ea8adc8c | 234 | |
6a06907d XL |
235 | Unlike arithmetic and logical operators, the traits for overloading these operators are used more generally to show how a type may be compared and will likely be assumed to define actual comparisons by functions that use these traits as bounds. |
236 | Many functions and macros in the standard library can then use that assumption (although not to ensure safety). | |
237 | Unlike the arithmetic and logical operators above, these operators implicitly take shared borrows of their operands, evaluating them in [place expression context][place expression]: | |
ea8adc8c | 238 | |
60c5eb7d XL |
239 | ```rust |
240 | # let a = 1; | |
241 | # let b = 1; | |
ea8adc8c XL |
242 | a == b; |
243 | // is equivalent to | |
244 | ::std::cmp::PartialEq::eq(&a, &b); | |
245 | ``` | |
246 | ||
247 | This means that the operands don't have to be moved out of. | |
248 | ||
249 | | Symbol | Meaning | Overloading method | | |
250 | |--------|--------------------------|----------------------------| | |
251 | | `==` | Equal | `std::cmp::PartialEq::eq` | | |
252 | | `!=` | Not equal | `std::cmp::PartialEq::ne` | | |
253 | | `>` | Greater than | `std::cmp::PartialOrd::gt` | | |
254 | | `<` | Less than | `std::cmp::PartialOrd::lt` | | |
255 | | `>=` | Greater than or equal to | `std::cmp::PartialOrd::ge` | | |
256 | | `<=` | Less than or equal to | `std::cmp::PartialOrd::le` | | |
257 | ||
258 | Here are examples of the comparison operators being used. | |
259 | ||
260 | ```rust | |
261 | assert!(123 == 123); | |
262 | assert!(23 != -12); | |
263 | assert!(12.5 > 12.2); | |
264 | assert!([1, 2, 3] < [1, 3, 4]); | |
265 | assert!('A' <= 'B'); | |
266 | assert!("World" >= "Hello"); | |
267 | ``` | |
268 | ||
269 | ## Lazy boolean operators | |
270 | ||
8faf50e0 XL |
271 | > **<sup>Syntax</sup>**\ |
272 | > _LazyBooleanExpression_ :\ | |
273 | > [_Expression_] `||` [_Expression_]\ | |
0531ce1d XL |
274 | > | [_Expression_] `&&` [_Expression_] |
275 | ||
6a06907d XL |
276 | The operators `||` and `&&` may be applied to operands of boolean type. |
277 | The `||` operator denotes logical 'or', and the `&&` operator denotes logical 'and'. | |
278 | They differ from `|` and `&` in that the right-hand operand is only evaluated when the left-hand operand does not already determine the result of the expression. | |
279 | That is, `||` only evaluates its right-hand operand when the left-hand operand evaluates to `false`, and `&&` only when it evaluates to `true`. | |
ea8adc8c XL |
280 | |
281 | ```rust | |
282 | let x = false || true; // true | |
283 | let y = false && panic!(); // false, doesn't evaluate `panic!()` | |
284 | ``` | |
285 | ||
286 | ## Type cast expressions | |
287 | ||
8faf50e0 XL |
288 | > **<sup>Syntax</sup>**\ |
289 | > _TypeCastExpression_ :\ | |
0bf4aa26 | 290 | > [_Expression_] `as` [_TypeNoBounds_] |
0531ce1d | 291 | |
ea8adc8c XL |
292 | A type cast expression is denoted with the binary operator `as`. |
293 | ||
6a06907d | 294 | Executing an `as` expression casts the value on the left-hand side to the type on the right-hand side. |
ea8adc8c XL |
295 | |
296 | An example of an `as` expression: | |
297 | ||
298 | ```rust | |
299 | # fn sum(values: &[f64]) -> f64 { 0.0 } | |
300 | # fn len(values: &[f64]) -> i32 { 0 } | |
301 | fn average(values: &[f64]) -> f64 { | |
302 | let sum: f64 = sum(values); | |
303 | let size: f64 = len(values) as f64; | |
304 | sum / size | |
305 | } | |
306 | ``` | |
307 | ||
6a06907d XL |
308 | `as` can be used to explicitly perform [coercions](../type-coercions.md), as well as the following additional casts. |
309 | Here `*T` means either `*const T` or `*mut T`. | |
ea8adc8c XL |
310 | |
311 | | Type of `e` | `U` | Cast performed by `e as U` | | |
312 | |-----------------------|-----------------------|----------------------------------| | |
313 | | Integer or Float type | Integer or Float type | Numeric cast | | |
314 | | C-like enum | Integer type | Enum cast | | |
315 | | `bool` or `char` | Integer type | Primitive to integer cast | | |
316 | | `u8` | `char` | `u8` to `char` cast | | |
317 | | `*T` | `*V` where `V: Sized` \* | Pointer to pointer cast | | |
6a06907d | 318 | | `*T` where `T: Sized` | Integer type | Pointer to address cast | |
ea8adc8c XL |
319 | | Integer type | `*V` where `V: Sized` | Address to pointer cast | |
320 | | `&[T; n]` | `*const T` | Array to pointer cast | | |
3dfed10e XL |
321 | | [Function item] | [Function pointer] | Function item to function pointer cast | |
322 | | [Function item] | `*V` where `V: Sized` | Function item to pointer cast | | |
323 | | [Function item] | Integer | Function item to address cast | | |
324 | | [Function pointer] | `*V` where `V: Sized` | Function pointer to pointer cast | | |
325 | | [Function pointer] | Integer | Function pointer to address cast | | |
94b46f34 | 326 | | Closure \*\* | Function pointer | Closure to function pointer cast | |
ea8adc8c | 327 | |
6a06907d | 328 | \* or `T` and `V` are compatible unsized types, e.g., both slices, both the same trait object. |
ea8adc8c | 329 | |
532ac7d7 | 330 | \*\* only for closures that do not capture (close over) any local variables |
94b46f34 | 331 | |
ea8adc8c XL |
332 | ### Semantics |
333 | ||
334 | * Numeric cast | |
335 | * Casting between two integers of the same size (e.g. i32 -> u32) is a no-op | |
336 | * Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will | |
337 | truncate | |
338 | * Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will | |
339 | * zero-extend if the source is unsigned | |
340 | * sign-extend if the source is signed | |
341 | * Casting from a float to an integer will round the float towards zero | |
f9f354fc XL |
342 | * `NaN` will return `0` |
343 | * Values larger than the maximum integer value will saturate to the | |
344 | maximum value of the integer type. | |
345 | * Values smaller than the minimum integer value will saturate to the | |
346 | minimum value of the integer type. | |
e1599b0c XL |
347 | * Casting from an integer to float will produce the closest possible float \* |
348 | * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* | |
349 | * on overflow, infinity (of the same sign as the input) is produced | |
350 | * note: with the current set of numeric types, overflow can only happen | |
351 | on `u128 as f32` for values greater or equal to `f32::MAX + (0.5 ULP)` | |
ea8adc8c | 352 | * Casting from an f32 to an f64 is perfect and lossless |
e1599b0c XL |
353 | * Casting from an f64 to an f32 will produce the closest possible f32 \*\* |
354 | * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* | |
355 | * on overflow, infinity (of the same sign as the input) is produced | |
ea8adc8c XL |
356 | * Enum cast |
357 | * Casts an enum to its discriminant, then uses a numeric cast if needed. | |
358 | * Primitive to integer cast | |
359 | * `false` casts to `0`, `true` casts to `1` | |
360 | * `char` casts to the value of the code point, then uses a numeric cast if needed. | |
361 | * `u8` to `char` cast | |
362 | * Casts to the `char` with the corresponding code point. | |
363 | ||
e1599b0c XL |
364 | \* if integer-to-float casts with this rounding mode and overflow behavior are |
365 | not supported natively by the hardware, these casts will likely be slower than | |
366 | expected. | |
367 | ||
368 | \*\* if f64-to-f32 casts with this rounding mode and overflow behavior are not | |
369 | supported natively by the hardware, these casts will likely be slower than | |
370 | expected. | |
371 | ||
372 | \*\*\* as defined in IEEE 754-2008 §4.3.1: pick the nearest floating point | |
373 | number, preferring the one with an even least significant digit if exactly | |
374 | halfway between two floating point numbers. | |
375 | ||
ea8adc8c XL |
376 | ## Assignment expressions |
377 | ||
8faf50e0 XL |
378 | > **<sup>Syntax</sup>**\ |
379 | > _AssignmentExpression_ :\ | |
48663c56 | 380 | > [_Expression_] `=` [_Expression_] |
0531ce1d | 381 | |
5869c6ff | 382 | An *assignment expression* moves a value into a specified place. |
ea8adc8c | 383 | |
6a06907d | 384 | An assignment expression consists of a [mutable] [place expression], the *assigned place operand*, followed by an equals sign (`=`) and a [value expression], the *assigned value operand*. |
5869c6ff | 385 | |
6a06907d XL |
386 | Unlike other place operands, the assigned place operand must be a place expression. |
387 | Attempting to use a value expression is a compiler error rather than promoting it to a temporary. | |
ea8adc8c | 388 | |
6a06907d XL |
389 | Evaluating assignment expressions begins by evaluating its operands. |
390 | The assigned value operand is evaluated first, followed by the assigned place operand. | |
5869c6ff | 391 | |
6a06907d | 392 | > **Note**: This is different than other expressions in that the right operand is evaluated before the left one. |
5869c6ff | 393 | |
6a06907d XL |
394 | It then has the effect of first [dropping] the value at the assigned place, unless the place is an uninitialized local variable or an uninitialized field of a local variable. |
395 | Next it either [copies or moves] the assigned value to the assigned place. | |
5869c6ff XL |
396 | |
397 | An assignment expression always produces [the unit value][unit]. | |
398 | ||
399 | Example: | |
400 | ||
ea8adc8c | 401 | ```rust |
5869c6ff XL |
402 | let mut x = 0; |
403 | let y = 0; | |
ea8adc8c XL |
404 | x = y; |
405 | ``` | |
406 | ||
407 | ## Compound assignment expressions | |
408 | ||
8faf50e0 XL |
409 | > **<sup>Syntax</sup>**\ |
410 | > _CompoundAssignmentExpression_ :\ | |
411 | > [_Expression_] `+=` [_Expression_]\ | |
412 | > | [_Expression_] `-=` [_Expression_]\ | |
413 | > | [_Expression_] `*=` [_Expression_]\ | |
414 | > | [_Expression_] `/=` [_Expression_]\ | |
415 | > | [_Expression_] `%=` [_Expression_]\ | |
416 | > | [_Expression_] `&=` [_Expression_]\ | |
417 | > | [_Expression_] `|=` [_Expression_]\ | |
418 | > | [_Expression_] `^=` [_Expression_]\ | |
419 | > | [_Expression_] `<<=` [_Expression_]\ | |
420 | > | [_Expression_] `>>=` [_Expression_] | |
0531ce1d | 421 | |
6a06907d | 422 | *Compound assignment expressions* combine arithmetic and logical binary operators with assignment expressions. |
5869c6ff XL |
423 | |
424 | For example: | |
425 | ||
426 | ```rust | |
427 | let mut x = 5; | |
428 | x += 1; | |
429 | assert!(x == 6); | |
430 | ``` | |
431 | ||
6a06907d | 432 | The syntax of compound assignment is a [mutable] [place expression], the *assigned operand*, then one of the operators followed by an `=` as a single token (no whitespace), and then a [value expression], the *modifying operand*. |
5869c6ff | 433 | |
6a06907d XL |
434 | Unlike other place operands, the assigned place operand must be a place expression. |
435 | Attempting to use a value expression is a compiler error rather than promoting it to a temporary. | |
5869c6ff | 436 | |
6a06907d | 437 | Evaluation of compound assignment expressions depends on the types of the operators. |
5869c6ff | 438 | |
6a06907d XL |
439 | If both types are primitives, then the modifying operand will be evaluated first followed by the assigned operand. |
440 | It will then set the value of the assigned operand's place to the value of performing the operation of the operator with the values of the assigned operand and modifying operand. | |
5869c6ff | 441 | |
6a06907d | 442 | > **Note**: This is different than other expressions in that the right operand is evaluated before the left one. |
5869c6ff | 443 | |
6a06907d XL |
444 | Otherwise, this expression is syntactic sugar for calling the function of the overloading compound assigment trait of the operator (see the table earlier in this chapter). |
445 | A mutable borrow of the assigned operand is automatically taken. | |
5869c6ff XL |
446 | |
447 | For example, the following expression statements in `example` are equivalent: | |
ea8adc8c XL |
448 | |
449 | ```rust | |
5869c6ff XL |
450 | # struct Addable; |
451 | # use std::ops::AddAssign; | |
452 | ||
453 | impl AddAssign<Addable> for Addable { | |
454 | /* */ | |
455 | # fn add_assign(&mut self, other: Addable) {} | |
456 | } | |
457 | ||
458 | fn example() { | |
459 | # let (mut a1, a2) = (Addable, Addable); | |
460 | a1 += a2; | |
461 | ||
462 | # let (mut a1, a2) = (Addable, Addable); | |
463 | AddAssign::add_assign(&mut a1, a2); | |
464 | } | |
ea8adc8c | 465 | ``` |
ff7c6d11 | 466 | |
5869c6ff XL |
467 | <div class="warning"> |
468 | ||
6a06907d XL |
469 | Warning: The evaluation order of operands swaps depending on the types of the operands: |
470 | with primitive types the right-hand side will get evaluated first, while with non-primitive types the left-hand side will get evaluated first. | |
471 | Try not to write code that depends on the evaluation order of operands in compound assignment expressions. | |
472 | See [this test] for an example of using this dependency. | |
5869c6ff XL |
473 | |
474 | </div> | |
475 | ||
476 | [copies or moves]: ../expressions.md#moved-and-copied-types | |
477 | [dropping]: ../destructors.md | |
6a06907d XL |
478 | [logical and]: ../types/boolean.md#logical-and |
479 | [logical not]: ../types/boolean.md#logical-not | |
480 | [logical or]: ../types/boolean.md#logical-or | |
481 | [logical xor]: ../types/boolean.md#logical-xor | |
5869c6ff | 482 | [mutable]: ../expressions.md#mutability |
416331ca | 483 | [place expression]: ../expressions.md#place-expressions-and-value-expressions |
5869c6ff | 484 | [unit]: ../types/tuple.md |
416331ca | 485 | [value expression]: ../expressions.md#place-expressions-and-value-expressions |
f9f354fc | 486 | [temporary value]: ../expressions.md#temporaries |
5869c6ff | 487 | [this test]: https://github.com/rust-lang/rust/blob/master/src/test/ui/expr/compound-assignment/eval-order.rs |
ff7c6d11 | 488 | [float-float]: https://github.com/rust-lang/rust/issues/15536 |
3dfed10e XL |
489 | [Function pointer]: ../types/function-pointer.md |
490 | [Function item]: ../types/function-item.md | |
0531ce1d XL |
491 | |
492 | [_BorrowExpression_]: #borrow-operators | |
493 | [_DereferenceExpression_]: #the-dereference-operator | |
494 | [_ErrorPropagationExpression_]: #the-question-mark-operator | |
495 | [_NegationExpression_]: #negation-operators | |
496 | [_ArithmeticOrLogicalExpression_]: #arithmetic-and-logical-binary-operators | |
497 | [_ComparisonExpression_]: #comparison-operators | |
498 | [_LazyBooleanExpression_]: #lazy-boolean-operators | |
499 | [_TypeCastExpression_]: #type-cast-expressions | |
500 | [_AssignmentExpression_]: #assignment-expressions | |
501 | [_CompoundAssignmentExpression_]: #compound-assignment-expressions | |
502 | ||
416331ca XL |
503 | [_Expression_]: ../expressions.md |
504 | [_TypeNoBounds_]: ../types.md#type-expressions |