]>
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`. | |
136023e0 | 28 | These checks occur even when `-C overflow-checks` is disabled, for legacy reasons. |
6a06907d | 29 | * 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 | 30 | |
ea8adc8c XL |
31 | ## Borrow operators |
32 | ||
8faf50e0 XL |
33 | > **<sup>Syntax</sup>**\ |
34 | > _BorrowExpression_ :\ | |
35 | > (`&`|`&&`) [_Expression_]\ | |
36 | > | (`&`|`&&`) `mut` [_Expression_] | |
0531ce1d | 37 | |
6a06907d XL |
38 | The `&` (shared borrow) and `&mut` (mutable borrow) operators are unary prefix operators. |
39 | When applied to a [place expression], this expressions produces a reference (pointer) to the location that the value refers to. | |
40 | The memory location is also placed into a borrowed state for the duration of the reference. | |
41 | For a shared borrow (`&`), this implies that the place may not be mutated, but it may be read or shared again. | |
42 | For a mutable borrow (`&mut`), the place may not be accessed in any way until the borrow expires. | |
43 | `&mut` evaluates its operand in a mutable place expression context. | |
44 | If the `&` or `&mut` operators are applied to a [value expression], then a [temporary value] is created. | |
ff7c6d11 XL |
45 | |
46 | These operators cannot be overloaded. | |
ea8adc8c XL |
47 | |
48 | ```rust | |
49 | { | |
50 | // a temporary with value 7 is created that lasts for this scope. | |
51 | let shared_reference = &7; | |
52 | } | |
53 | let mut array = [-2, 3, 9]; | |
54 | { | |
55 | // Mutably borrows `array` for this scope. | |
56 | // `array` may only be used through `mutable_reference`. | |
57 | let mutable_reference = &mut array; | |
58 | } | |
59 | ``` | |
60 | ||
6a06907d | 61 | 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 |
62 | |
63 | ```rust | |
64 | // same meanings: | |
65 | let a = && 10; | |
66 | let a = & & 10; | |
67 | ||
68 | // same meanings: | |
69 | let a = &&&& mut 10; | |
70 | let a = && && mut 10; | |
71 | let a = & & & & mut 10; | |
72 | ``` | |
73 | ||
ea8adc8c XL |
74 | ## The dereference operator |
75 | ||
8faf50e0 XL |
76 | > **<sup>Syntax</sup>**\ |
77 | > _DereferenceExpression_ :\ | |
0531ce1d XL |
78 | > `*` [_Expression_] |
79 | ||
6a06907d XL |
80 | The `*` (dereference) operator is also a unary prefix operator. |
81 | When applied to a [pointer](../types/pointer.md) it denotes the pointed-to location. | |
82 | 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 | 83 | Dereferencing a raw pointer requires `unsafe`. |
ea8adc8c | 84 | |
6a06907d | 85 | 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 |
86 | |
87 | ```rust | |
88 | let x = &7; | |
89 | assert_eq!(*x, 7); | |
90 | let y = &mut 9; | |
91 | *y = 11; | |
92 | assert_eq!(*y, 11); | |
93 | ``` | |
94 | ||
ff7c6d11 XL |
95 | ## The question mark operator |
96 | ||
8faf50e0 XL |
97 | > **<sup>Syntax</sup>**\ |
98 | > _ErrorPropagationExpression_ :\ | |
99 | > [_Expression_] `?` | |
0531ce1d | 100 | |
6a06907d XL |
101 | The question mark operator (`?`) unwraps valid values or returns erroneous values, propagating them to the calling function. |
102 | It is a unary postfix operator that can only be applied to the types `Result<T, E>` and `Option<T>`. | |
ea8adc8c | 103 | |
6a06907d XL |
104 | When applied to values of the `Result<T, E>` type, it propagates errors. |
105 | If the value is `Err(e)`, then it will return `Err(From::from(e))` from the enclosing function or closure. | |
106 | If applied to `Ok(x)`, then it will unwrap the value to evaluate to `x`. | |
ea8adc8c XL |
107 | |
108 | ```rust | |
109 | # use std::num::ParseIntError; | |
110 | fn try_to_parse() -> Result<i32, ParseIntError> { | |
111 | let x: i32 = "123".parse()?; // x = 123 | |
112 | let y: i32 = "24a".parse()?; // returns an Err() immediately | |
113 | Ok(x + y) // Doesn't run. | |
114 | } | |
115 | ||
116 | let res = try_to_parse(); | |
117 | println!("{:?}", res); | |
118 | # assert!(res.is_err()) | |
119 | ``` | |
120 | ||
6a06907d XL |
121 | When applied to values of the `Option<T>` type, it propagates `None`s. |
122 | If the value is `None`, then it will return `None`. | |
123 | If applied to `Some(x)`, then it will unwrap the value to evaluate to `x`. | |
ff7c6d11 XL |
124 | |
125 | ```rust | |
126 | fn try_option_some() -> Option<u8> { | |
127 | let val = Some(1)?; | |
128 | Some(val) | |
129 | } | |
130 | assert_eq!(try_option_some(), Some(1)); | |
131 | ||
132 | fn try_option_none() -> Option<u8> { | |
133 | let val = None?; | |
134 | Some(val) | |
135 | } | |
136 | assert_eq!(try_option_none(), None); | |
137 | ``` | |
138 | ||
139 | `?` cannot be overloaded. | |
140 | ||
ea8adc8c XL |
141 | ## Negation operators |
142 | ||
8faf50e0 XL |
143 | > **<sup>Syntax</sup>**\ |
144 | > _NegationExpression_ :\ | |
145 | > `-` [_Expression_]\ | |
146 | > | `!` [_Expression_] | |
0531ce1d | 147 | |
6a06907d XL |
148 | These are the last two unary operators. |
149 | This table summarizes the behavior of them on primitive types and which traits are used to overload these operators for other types. | |
150 | Remember that signed integers are always represented using two's complement. | |
151 | The operands of all of these operators are evaluated in [value expression context][value expression] so are moved or copied. | |
ea8adc8c | 152 | |
6a06907d XL |
153 | | Symbol | Integer | `bool` | Floating Point | Overloading Trait | |
154 | |--------|-------------|-------------- |----------------|--------------------| | |
155 | | `-` | Negation* | | Negation | `std::ops::Neg` | | |
156 | | `!` | Bitwise NOT | [Logical NOT] | | `std::ops::Not` | | |
ea8adc8c XL |
157 | |
158 | \* Only for signed integer types. | |
159 | ||
160 | Here are some example of these operators | |
161 | ||
162 | ```rust | |
163 | let x = 6; | |
164 | assert_eq!(-x, -6); | |
165 | assert_eq!(!x, -7); | |
166 | assert_eq!(true, !false); | |
167 | ``` | |
168 | ||
169 | ## Arithmetic and Logical Binary Operators | |
170 | ||
8faf50e0 XL |
171 | > **<sup>Syntax</sup>**\ |
172 | > _ArithmeticOrLogicalExpression_ :\ | |
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_]\ | |
182 | > | [_Expression_] `>>` [_Expression_] | |
0531ce1d | 183 | |
6a06907d XL |
184 | Binary operators expressions are all written with infix notation. |
185 | 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. | |
186 | Remember that signed integers are always represented using two's complement. | |
187 | The operands of all of these operators are evaluated in [value expression context][value expression] so are moved or copied. | |
188 | ||
189 | | Symbol | Integer | `bool` | Floating Point | Overloading Trait | Overloading Compound Assignment Trait | | |
190 | |--------|-------------------------|---------------|----------------|--------------------| ------------------------------------- | | |
191 | | `+` | Addition | | Addition | `std::ops::Add` | `std::ops::AddAssign` | | |
192 | | `-` | Subtraction | | Subtraction | `std::ops::Sub` | `std::ops::SubAssign` | | |
193 | | `*` | Multiplication | | Multiplication | `std::ops::Mul` | `std::ops::MulAssign` | | |
194 | | `/` | Division* | | Division | `std::ops::Div` | `std::ops::DivAssign` | | |
136023e0 | 195 | | `%` | Remainder** | | Remainder | `std::ops::Rem` | `std::ops::RemAssign` | |
6a06907d XL |
196 | | `&` | Bitwise AND | [Logical AND] | | `std::ops::BitAnd` | `std::ops::BitAndAssign` | |
197 | | <code>|</code> | Bitwise OR | [Logical OR] | | `std::ops::BitOr` | `std::ops::BitOrAssign` | | |
198 | | `^` | Bitwise XOR | [Logical XOR] | | `std::ops::BitXor` | `std::ops::BitXorAssign` | | |
199 | | `<<` | Left Shift | | | `std::ops::Shl` | `std::ops::ShlAssign` | | |
136023e0 | 200 | | `>>` | Right Shift*** | | | `std::ops::Shr` | `std::ops::ShrAssign` | |
ea8adc8c | 201 | |
94b46f34 XL |
202 | \* Integer division rounds towards zero. |
203 | ||
136023e0 XL |
204 | \*\* Rust uses a remainder defined with [truncating division](https://en.wikipedia.org/wiki/Modulo_operation#Variants_of_the_definition). Given `remainder = dividend % divisor`, the remainder will have the same sign as the dividend. |
205 | ||
206 | \*\*\* Arithmetic right shift on signed integer types, logical right shift on | |
ea8adc8c XL |
207 | unsigned integer types. |
208 | ||
209 | Here are examples of these operators being used. | |
210 | ||
211 | ```rust | |
212 | assert_eq!(3 + 6, 9); | |
213 | assert_eq!(5.5 - 1.25, 4.25); | |
214 | assert_eq!(-5 * 14, -70); | |
215 | assert_eq!(14 / 3, 4); | |
216 | assert_eq!(100 % 7, 2); | |
217 | assert_eq!(0b1010 & 0b1100, 0b1000); | |
218 | assert_eq!(0b1010 | 0b1100, 0b1110); | |
219 | assert_eq!(0b1010 ^ 0b1100, 0b110); | |
220 | assert_eq!(13 << 3, 104); | |
221 | assert_eq!(-10 >> 2, -3); | |
222 | ``` | |
223 | ||
224 | ## Comparison Operators | |
225 | ||
8faf50e0 XL |
226 | > **<sup>Syntax</sup>**\ |
227 | > _ComparisonExpression_ :\ | |
228 | > [_Expression_] `==` [_Expression_]\ | |
229 | > | [_Expression_] `!=` [_Expression_]\ | |
230 | > | [_Expression_] `>` [_Expression_]\ | |
231 | > | [_Expression_] `<` [_Expression_]\ | |
232 | > | [_Expression_] `>=` [_Expression_]\ | |
233 | > | [_Expression_] `<=` [_Expression_] | |
0531ce1d | 234 | |
6a06907d XL |
235 | Comparison operators are also defined both for primitive types and many types in the standard library. |
236 | 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 | 237 | |
6a06907d XL |
238 | 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. |
239 | Many functions and macros in the standard library can then use that assumption (although not to ensure safety). | |
240 | 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 | 241 | |
60c5eb7d XL |
242 | ```rust |
243 | # let a = 1; | |
244 | # let b = 1; | |
ea8adc8c XL |
245 | a == b; |
246 | // is equivalent to | |
247 | ::std::cmp::PartialEq::eq(&a, &b); | |
248 | ``` | |
249 | ||
250 | This means that the operands don't have to be moved out of. | |
251 | ||
252 | | Symbol | Meaning | Overloading method | | |
253 | |--------|--------------------------|----------------------------| | |
254 | | `==` | Equal | `std::cmp::PartialEq::eq` | | |
255 | | `!=` | Not equal | `std::cmp::PartialEq::ne` | | |
256 | | `>` | Greater than | `std::cmp::PartialOrd::gt` | | |
257 | | `<` | Less than | `std::cmp::PartialOrd::lt` | | |
258 | | `>=` | Greater than or equal to | `std::cmp::PartialOrd::ge` | | |
259 | | `<=` | Less than or equal to | `std::cmp::PartialOrd::le` | | |
260 | ||
261 | Here are examples of the comparison operators being used. | |
262 | ||
263 | ```rust | |
264 | assert!(123 == 123); | |
265 | assert!(23 != -12); | |
266 | assert!(12.5 > 12.2); | |
267 | assert!([1, 2, 3] < [1, 3, 4]); | |
268 | assert!('A' <= 'B'); | |
269 | assert!("World" >= "Hello"); | |
270 | ``` | |
271 | ||
272 | ## Lazy boolean operators | |
273 | ||
8faf50e0 XL |
274 | > **<sup>Syntax</sup>**\ |
275 | > _LazyBooleanExpression_ :\ | |
276 | > [_Expression_] `||` [_Expression_]\ | |
0531ce1d XL |
277 | > | [_Expression_] `&&` [_Expression_] |
278 | ||
6a06907d XL |
279 | The operators `||` and `&&` may be applied to operands of boolean type. |
280 | The `||` operator denotes logical 'or', and the `&&` operator denotes logical 'and'. | |
281 | 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. | |
282 | 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 |
283 | |
284 | ```rust | |
285 | let x = false || true; // true | |
286 | let y = false && panic!(); // false, doesn't evaluate `panic!()` | |
287 | ``` | |
288 | ||
289 | ## Type cast expressions | |
290 | ||
8faf50e0 XL |
291 | > **<sup>Syntax</sup>**\ |
292 | > _TypeCastExpression_ :\ | |
0bf4aa26 | 293 | > [_Expression_] `as` [_TypeNoBounds_] |
0531ce1d | 294 | |
ea8adc8c XL |
295 | A type cast expression is denoted with the binary operator `as`. |
296 | ||
6a06907d | 297 | Executing an `as` expression casts the value on the left-hand side to the type on the right-hand side. |
ea8adc8c XL |
298 | |
299 | An example of an `as` expression: | |
300 | ||
301 | ```rust | |
302 | # fn sum(values: &[f64]) -> f64 { 0.0 } | |
303 | # fn len(values: &[f64]) -> i32 { 0 } | |
304 | fn average(values: &[f64]) -> f64 { | |
305 | let sum: f64 = sum(values); | |
306 | let size: f64 = len(values) as f64; | |
307 | sum / size | |
308 | } | |
309 | ``` | |
310 | ||
6a06907d | 311 | `as` can be used to explicitly perform [coercions](../type-coercions.md), as well as the following additional casts. |
cdc7bbd5 XL |
312 | Any cast that does not fit either a coercion rule or an entry in the table is a compiler error. |
313 | Here `*T` means either `*const T` or `*mut T`. `m` stands for optional `mut` in | |
314 | reference types and `mut` or `const` in pointer types. | |
ea8adc8c XL |
315 | |
316 | | Type of `e` | `U` | Cast performed by `e as U` | | |
317 | |-----------------------|-----------------------|----------------------------------| | |
318 | | Integer or Float type | Integer or Float type | Numeric cast | | |
319 | | C-like enum | Integer type | Enum cast | | |
320 | | `bool` or `char` | Integer type | Primitive to integer cast | | |
321 | | `u8` | `char` | `u8` to `char` cast | | |
322 | | `*T` | `*V` where `V: Sized` \* | Pointer to pointer cast | | |
6a06907d | 323 | | `*T` where `T: Sized` | Integer type | Pointer to address cast | |
ea8adc8c | 324 | | Integer type | `*V` where `V: Sized` | Address to pointer cast | |
cdc7bbd5 XL |
325 | | `&m₁ T` | `*m₂ T` \*\* | Reference to pointer cast | |
326 | | `&m₁ [T; n]` | `*m₂ T` \*\* | Array to pointer cast | | |
3dfed10e XL |
327 | | [Function item] | [Function pointer] | Function item to function pointer cast | |
328 | | [Function item] | `*V` where `V: Sized` | Function item to pointer cast | | |
329 | | [Function item] | Integer | Function item to address cast | | |
330 | | [Function pointer] | `*V` where `V: Sized` | Function pointer to pointer cast | | |
331 | | [Function pointer] | Integer | Function pointer to address cast | | |
cdc7bbd5 | 332 | | Closure \*\*\* | Function pointer | Closure to function pointer cast | |
ea8adc8c | 333 | |
6a06907d | 334 | \* or `T` and `V` are compatible unsized types, e.g., both slices, both the same trait object. |
ea8adc8c | 335 | |
cdc7bbd5 XL |
336 | \*\* only when `m₁` is `mut` or `m₂` is `const`. Casting `mut` reference to |
337 | `const` pointer is allowed. | |
338 | ||
339 | \*\*\* only for closures that do not capture (close over) any local variables | |
94b46f34 | 340 | |
ea8adc8c XL |
341 | ### Semantics |
342 | ||
17df50a5 XL |
343 | #### Numeric cast |
344 | ||
345 | * Casting between two integers of the same size (e.g. i32 -> u32) is a no-op | |
136023e0 | 346 | (Rust uses 2's complement for negative values of fixed integers) |
17df50a5 XL |
347 | * Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will |
348 | truncate | |
349 | * Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will | |
350 | * zero-extend if the source is unsigned | |
351 | * sign-extend if the source is signed | |
352 | * Casting from a float to an integer will round the float towards zero | |
353 | * `NaN` will return `0` | |
136023e0 XL |
354 | * Values larger than the maximum integer value, including `INFINITY`, will saturate to the maximum value of the integer type. |
355 | * Values smaller than the minimum integer value, including `NEG_INFINITY`, will saturate to the minimum value of the integer type. | |
17df50a5 XL |
356 | * Casting from an integer to float will produce the closest possible float \* |
357 | * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* | |
358 | * on overflow, infinity (of the same sign as the input) is produced | |
359 | * note: with the current set of numeric types, overflow can only happen | |
360 | on `u128 as f32` for values greater or equal to `f32::MAX + (0.5 ULP)` | |
361 | * Casting from an f32 to an f64 is perfect and lossless | |
362 | * Casting from an f64 to an f32 will produce the closest possible f32 \*\* | |
363 | * if necessary, rounding is according to `roundTiesToEven` mode \*\*\* | |
364 | * on overflow, infinity (of the same sign as the input) is produced | |
ea8adc8c | 365 | |
e1599b0c XL |
366 | \* if integer-to-float casts with this rounding mode and overflow behavior are |
367 | not supported natively by the hardware, these casts will likely be slower than | |
368 | expected. | |
369 | ||
370 | \*\* if f64-to-f32 casts with this rounding mode and overflow behavior are not | |
371 | supported natively by the hardware, these casts will likely be slower than | |
372 | expected. | |
373 | ||
374 | \*\*\* as defined in IEEE 754-2008 §4.3.1: pick the nearest floating point | |
375 | number, preferring the one with an even least significant digit if exactly | |
376 | halfway between two floating point numbers. | |
377 | ||
17df50a5 XL |
378 | #### Enum cast |
379 | ||
380 | Casts an enum to its discriminant, then uses a numeric cast if needed. | |
381 | ||
382 | #### Primitive to integer cast | |
383 | ||
384 | * `false` casts to `0`, `true` casts to `1` | |
385 | * `char` casts to the value of the code point, then uses a numeric cast if needed. | |
386 | ||
387 | #### `u8` to `char` cast | |
388 | ||
389 | Casts to the `char` with the corresponding code point. | |
390 | ||
391 | #### Pointer to address cast | |
392 | ||
393 | Casting from a raw pointer to an integer produces the machine address of the referenced memory. | |
394 | If the integer type is smaller than the pointer type, the address may be truncated; using `usize` avoids this. | |
395 | ||
396 | #### Address to pointer cast | |
397 | ||
398 | Casting from an integer to a raw pointer interprets the integer as a memory address and produces a pointer referencing that memory. | |
399 | ||
400 | <div class="warning"> | |
401 | ||
402 | Warning: | |
403 | This interacts with the Rust memory model, which is still under development. | |
404 | A pointer obtained from this cast may suffer additional restrictions even if it is bitwise equal to a valid pointer. | |
405 | Dereferencing such a pointer may be [undefined behavior] if aliasing rules are not followed. | |
406 | ||
407 | </div> | |
408 | ||
409 | A trivial example of sound address arithmetic: | |
410 | ||
411 | ```rust | |
412 | let mut values: [i32; 2] = [1, 2]; | |
413 | let p1: *mut i32 = values.as_mut_ptr(); | |
414 | let first_address = p1 as usize; | |
415 | let second_address = first_address + 4; // 4 == size_of::<i32>() | |
416 | let p2 = second_address as *mut i32; | |
417 | unsafe { | |
418 | *p2 += 1; | |
419 | } | |
420 | assert_eq!(values[1], 3); | |
421 | ``` | |
422 | ||
ea8adc8c XL |
423 | ## Assignment expressions |
424 | ||
8faf50e0 XL |
425 | > **<sup>Syntax</sup>**\ |
426 | > _AssignmentExpression_ :\ | |
48663c56 | 427 | > [_Expression_] `=` [_Expression_] |
0531ce1d | 428 | |
5869c6ff | 429 | An *assignment expression* moves a value into a specified place. |
ea8adc8c | 430 | |
5099ac24 FG |
431 | An assignment expression consists of a [mutable] [assignee expression], the *assignee operand*, followed by an equals sign (`=`) and a [value expression], the *assigned value operand*. |
432 | In its most basic form, an assignee expression is a [place expression], and we discuss this case first. | |
433 | The more general case of destructuring assignment is discussed below, but this case always decomposes into sequential assignments to place expressions, which may be considered the more fundamental case. | |
5869c6ff | 434 | |
5099ac24 | 435 | ### Basic assignments |
ea8adc8c | 436 | |
6a06907d | 437 | Evaluating assignment expressions begins by evaluating its operands. |
5099ac24 FG |
438 | The assigned value operand is evaluated first, followed by the assignee expression. |
439 | For destructuring assignment, subexpressions of the assignee expression are evaluated left-to-right. | |
5869c6ff | 440 | |
6a06907d | 441 | > **Note**: This is different than other expressions in that the right operand is evaluated before the left one. |
5869c6ff | 442 | |
6a06907d XL |
443 | 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. |
444 | Next it either [copies or moves] the assigned value to the assigned place. | |
5869c6ff XL |
445 | |
446 | An assignment expression always produces [the unit value][unit]. | |
447 | ||
448 | Example: | |
449 | ||
ea8adc8c | 450 | ```rust |
5869c6ff XL |
451 | let mut x = 0; |
452 | let y = 0; | |
ea8adc8c XL |
453 | x = y; |
454 | ``` | |
455 | ||
5099ac24 FG |
456 | ### Destructuring assignments |
457 | ||
458 | Destructuring assignment is a counterpart to destructuring pattern matches for variable declaration, permitting assignment to complex values, such as tuples or structs. | |
459 | For instance, we may swap two mutable variables: | |
460 | ||
461 | ```rust | |
462 | let (mut a, mut b) = (0, 1); | |
463 | // Swap `a` and `b` using destructuring assignment. | |
464 | (b, a) = (a, b); | |
465 | ``` | |
466 | ||
467 | In contrast to destructuring declarations using `let`, patterns may not appear on the left-hand side of an assignment due to syntactic ambiguities. | |
468 | Instead, a group of expressions that correspond to patterns are designated to be [assignee expressions][assignee expression], and permitted on the left-hand side of an assignment. | |
469 | Assignee expressions are then desugared to pattern matches followed by sequential assignment. | |
470 | The desugared patterns must be irrefutable: in particular, this means that only slice patterns whose length is known at compile-time, and the trivial slice `[..]`, are permitted for destructuring assignment. | |
471 | ||
472 | The desugaring method is straightforward, and is illustrated best by example. | |
473 | ||
474 | ```rust | |
475 | # struct Struct { x: u32, y: u32 } | |
476 | # let (mut a, mut b) = (0, 0); | |
477 | (a, b) = (3, 4); | |
478 | ||
479 | [a, b] = [3, 4]; | |
480 | ||
481 | Struct { x: a, y: b } = Struct { x: 3, y: 4}; | |
482 | ||
483 | // desugars to: | |
484 | ||
485 | { | |
486 | let (_a, _b) = (3, 4); | |
487 | a = _a; | |
488 | b = _b; | |
489 | } | |
490 | ||
491 | { | |
492 | let [_a, _b] = [3, 4]; | |
493 | a = _a; | |
494 | b = _b; | |
495 | } | |
496 | ||
497 | { | |
498 | let Struct { x: _a, y: _b } = Struct { x: 3, y: 4}; | |
499 | a = _a; | |
500 | b = _b; | |
501 | } | |
502 | ``` | |
503 | ||
504 | Identifiers are not forbidden from being used multiple times in a single assignee expression. | |
505 | ||
506 | [Underscore expressions][_UnderscoreExpression_] and empty [range expressions][_RangeExpression_] may be used to ignore certain values, without binding them. | |
507 | ||
508 | Note that default binding modes do not apply for the desugared expression. | |
509 | ||
ea8adc8c XL |
510 | ## Compound assignment expressions |
511 | ||
8faf50e0 XL |
512 | > **<sup>Syntax</sup>**\ |
513 | > _CompoundAssignmentExpression_ :\ | |
514 | > [_Expression_] `+=` [_Expression_]\ | |
515 | > | [_Expression_] `-=` [_Expression_]\ | |
516 | > | [_Expression_] `*=` [_Expression_]\ | |
517 | > | [_Expression_] `/=` [_Expression_]\ | |
518 | > | [_Expression_] `%=` [_Expression_]\ | |
519 | > | [_Expression_] `&=` [_Expression_]\ | |
520 | > | [_Expression_] `|=` [_Expression_]\ | |
521 | > | [_Expression_] `^=` [_Expression_]\ | |
522 | > | [_Expression_] `<<=` [_Expression_]\ | |
523 | > | [_Expression_] `>>=` [_Expression_] | |
0531ce1d | 524 | |
6a06907d | 525 | *Compound assignment expressions* combine arithmetic and logical binary operators with assignment expressions. |
5869c6ff XL |
526 | |
527 | For example: | |
528 | ||
529 | ```rust | |
530 | let mut x = 5; | |
531 | x += 1; | |
532 | assert!(x == 6); | |
533 | ``` | |
534 | ||
6a06907d | 535 | 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 | 536 | |
6a06907d XL |
537 | Unlike other place operands, the assigned place operand must be a place expression. |
538 | Attempting to use a value expression is a compiler error rather than promoting it to a temporary. | |
5869c6ff | 539 | |
6a06907d | 540 | Evaluation of compound assignment expressions depends on the types of the operators. |
5869c6ff | 541 | |
6a06907d XL |
542 | If both types are primitives, then the modifying operand will be evaluated first followed by the assigned operand. |
543 | 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 | 544 | |
6a06907d | 545 | > **Note**: This is different than other expressions in that the right operand is evaluated before the left one. |
5869c6ff | 546 | |
6a06907d XL |
547 | 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). |
548 | A mutable borrow of the assigned operand is automatically taken. | |
5869c6ff XL |
549 | |
550 | For example, the following expression statements in `example` are equivalent: | |
ea8adc8c XL |
551 | |
552 | ```rust | |
5869c6ff XL |
553 | # struct Addable; |
554 | # use std::ops::AddAssign; | |
555 | ||
556 | impl AddAssign<Addable> for Addable { | |
557 | /* */ | |
558 | # fn add_assign(&mut self, other: Addable) {} | |
559 | } | |
560 | ||
561 | fn example() { | |
562 | # let (mut a1, a2) = (Addable, Addable); | |
563 | a1 += a2; | |
564 | ||
565 | # let (mut a1, a2) = (Addable, Addable); | |
566 | AddAssign::add_assign(&mut a1, a2); | |
567 | } | |
ea8adc8c | 568 | ``` |
ff7c6d11 | 569 | |
17df50a5 XL |
570 | Like assignment expressions, compound assignment expressions always produce [the unit value][unit]. |
571 | ||
5869c6ff XL |
572 | <div class="warning"> |
573 | ||
6a06907d XL |
574 | Warning: The evaluation order of operands swaps depending on the types of the operands: |
575 | with primitive types the right-hand side will get evaluated first, while with non-primitive types the left-hand side will get evaluated first. | |
576 | Try not to write code that depends on the evaluation order of operands in compound assignment expressions. | |
577 | See [this test] for an example of using this dependency. | |
5869c6ff XL |
578 | |
579 | </div> | |
580 | ||
581 | [copies or moves]: ../expressions.md#moved-and-copied-types | |
582 | [dropping]: ../destructors.md | |
6a06907d XL |
583 | [logical and]: ../types/boolean.md#logical-and |
584 | [logical not]: ../types/boolean.md#logical-not | |
585 | [logical or]: ../types/boolean.md#logical-or | |
586 | [logical xor]: ../types/boolean.md#logical-xor | |
5869c6ff | 587 | [mutable]: ../expressions.md#mutability |
416331ca | 588 | [place expression]: ../expressions.md#place-expressions-and-value-expressions |
5099ac24 | 589 | [assignee expression]: ../expressions.md#place-expressions-and-value-expressions |
17df50a5 | 590 | [undefined behavior]: ../behavior-considered-undefined.md |
5869c6ff | 591 | [unit]: ../types/tuple.md |
416331ca | 592 | [value expression]: ../expressions.md#place-expressions-and-value-expressions |
f9f354fc | 593 | [temporary value]: ../expressions.md#temporaries |
5099ac24 | 594 | [this test]: https://github.com/rust-lang/rust/blob/1.58.0/src/test/ui/expr/compound-assignment/eval-order.rs |
ff7c6d11 | 595 | [float-float]: https://github.com/rust-lang/rust/issues/15536 |
3dfed10e XL |
596 | [Function pointer]: ../types/function-pointer.md |
597 | [Function item]: ../types/function-item.md | |
0531ce1d XL |
598 | |
599 | [_BorrowExpression_]: #borrow-operators | |
600 | [_DereferenceExpression_]: #the-dereference-operator | |
601 | [_ErrorPropagationExpression_]: #the-question-mark-operator | |
602 | [_NegationExpression_]: #negation-operators | |
603 | [_ArithmeticOrLogicalExpression_]: #arithmetic-and-logical-binary-operators | |
604 | [_ComparisonExpression_]: #comparison-operators | |
605 | [_LazyBooleanExpression_]: #lazy-boolean-operators | |
606 | [_TypeCastExpression_]: #type-cast-expressions | |
607 | [_AssignmentExpression_]: #assignment-expressions | |
608 | [_CompoundAssignmentExpression_]: #compound-assignment-expressions | |
609 | ||
416331ca XL |
610 | [_Expression_]: ../expressions.md |
611 | [_TypeNoBounds_]: ../types.md#type-expressions | |
5099ac24 FG |
612 | [_RangeExpression_]: ./range-expr.md |
613 | [_UnderscoreExpression_]: ./underscore-expr.md |