From 7e33fb96604beaa5fa214b3d58fb0f24cfa472b0 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 12:59:53 +0000 Subject: [PATCH 01/44] Alway wrap text in expressions.md at 80 characters --- src/expressions.md | 103 ++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index d69afc2a6a620..269d42eaa4acd 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -8,7 +8,8 @@ several things: * Whether or not to evaluate the sub-expressions when evaluating the expression * The order in which to evaluate the sub-expressions -* How to combine the sub-expressions' values to obtain the value of the expression +* How to combine the sub-expressions' values to obtain the value of the + expression In this way, the structure of expressions dictates the structure of execution. Blocks are just another kind of expression, so blocks, statements, expressions, @@ -41,19 +42,19 @@ that memory location. #### Temporary lifetimes -When an rvalue is used in an lvalue context, a temporary un-named -lvalue is created and used instead. The lifetime of temporary values -is typically the innermost enclosing statement; the tail expression of -a block is considered part of the statement that encloses the block. +When an rvalue is used in an lvalue context, a temporary un-named lvalue is +created and used instead. The lifetime of temporary values is typically the +innermost enclosing statement; the tail expression of a block is considered +part of the statement that encloses the block. When a temporary rvalue is being created that is assigned into a `let` -declaration, however, the temporary is created with the lifetime of -the enclosing block instead, as using the enclosing statement (the -`let` declaration) would be a guaranteed error (since a pointer to the -temporary would be stored into a variable, but the temporary would be -freed before the variable could be used). The compiler uses simple -syntactic rules to decide which values are being assigned into a `let` -binding, and therefore deserve a longer temporary lifetime. +declaration, however, the temporary is created with the lifetime of the +enclosing block instead, as using the enclosing statement (the `let` +declaration) would be a guaranteed error (since a pointer to the temporary +would be stored into a variable, but the temporary would be freed before the +variable could be used). The compiler uses simple syntactic rules to decide +which values are being assigned into a `let` binding, and therefore deserve a +longer temporary lifetime. Here are some examples: @@ -85,9 +86,9 @@ be copied if its type implements `Copy`. All others are moved. ## Literal expressions -A _literal expression_ consists of one of the [literal](tokens.html#literals) forms -described earlier. It directly describes a number, character, string, boolean -value, or the unit value. +A _literal expression_ consists of one of the [literal](tokens.html#literals) +forms described earlier. It directly describes a number, character, string, +boolean value, or the unit value. ```rust (); // unit type @@ -123,11 +124,11 @@ comma: ## Struct expressions -There are several forms of struct expressions. A _struct expression_ -consists of the [path](paths.html) of a [struct item](items.html#structs), followed -by a brace-enclosed list of zero or more comma-separated name-value pairs, +There are several forms of struct expressions. A _struct expression_ consists +of the [path](paths.html) of a [struct item](items.html#structs), followed by a +brace-enclosed list of zero or more comma-separated name-value pairs, providing the field values of a new instance of the struct. A field name can be -any identifier, and is separated from its value expression by a colon. The +any identifier, and is separated from its value expression by a colon. The location denoted by a struct field is mutable if and only if the enclosing struct is mutable. @@ -154,9 +155,8 @@ let u = game::User {name: "Joe", age: 35, score: 100_000}; some_fn::(Cookie); ``` -A struct expression forms a new value of the named struct type. Note -that for a given *unit-like* struct type, this will always be the same -value. +A struct expression forms a new value of the named struct type. Note that for a +given *unit-like* struct type, this will always be the same value. A struct expression can terminate with the syntax `..` followed by an expression to denote a functional update. The expression following `..` (the @@ -237,10 +237,9 @@ A field access is an [lvalue](expressions.html#lvalues-rvalues-and-temporaries) referring to the value of that field. When the type providing the field inherits mutability, it can be [assigned](#assignment-expressions) to. -Also, if the type of the expression to the left of the dot is a -pointer, it is automatically dereferenced as many times as necessary -to make the field access possible. In cases of ambiguity, we prefer -fewer autoderefs to more. +Also, if the type of the expression to the left of the dot is a pointer, it is +automatically dereferenced as many times as necessary to make the field access +possible. In cases of ambiguity, we prefer fewer autoderefs to more. ## Array expressions @@ -283,10 +282,9 @@ let arr = ["a", "b"]; arr[10]; // panics ``` -Also, if the type of the expression to the left of the brackets is a -pointer, it is automatically dereferenced as many times as necessary -to make the indexing possible. In cases of ambiguity, we prefer fewer -autoderefs to more. +Also, if the type of the expression to the left of the brackets is a pointer, +it is automatically dereferenced as many times as necessary to make the +indexing possible. In cases of ambiguity, we prefer fewer autoderefs to more. ## Range expressions @@ -475,12 +473,12 @@ fn average(values: &[f64]) -> f64 { } ``` -Some of the conversions which can be done through the `as` operator -can also be done implicitly at various points in the program, such as -argument passing and assignment to a `let` binding with an explicit -type. Implicit conversions are limited to "harmless" conversions that -do not lose information and which have minimal or no risk of -surprising side-effects on the dynamic execution semantics. +Some of the conversions which can be done through the `as` operator can also be +done implicitly at various points in the program, such as argument passing and +assignment to a `let` binding with an explicit type. Implicit conversions are +limited to "harmless" conversions that do not lose information and which have +minimal or no risk of surprising side-effects on the dynamic execution +semantics. ### Assignment expressions @@ -609,11 +607,11 @@ ten_times(move |j| println!("{}, {}", word, j)); A `loop` expression denotes an infinite loop. -A `loop` expression may optionally have a _label_. The label is written as -a lifetime preceding the loop expression, as in `'foo: loop{ }`. If a -label is present, then labeled `break` and `continue` expressions nested -within this loop may exit out of this loop or return control to its head. -See [break expressions](#break-expressions) and [continue +A `loop` expression may optionally have a _label_. The label is written as a +lifetime preceding the loop expression, as in `'foo: loop{ }`. If a label is +present, then labeled `break` and `continue` expressions nested within this +loop may exit out of this loop or return control to its head. See [break +expressions](#break-expressions) and [continue expressions](#continue-expressions). ## `break` expressions @@ -621,8 +619,9 @@ expressions](#continue-expressions). A `break` expression has an optional _label_. If the label is absent, then executing a `break` expression immediately terminates the innermost loop enclosing it. It is only permitted in the body of a loop. If the label is -present, then `break 'foo` terminates the loop with label `'foo`, which need not -be the innermost label enclosing the `break` expression, but must enclose it. +present, then `break 'foo` terminates the loop with label `'foo`, which need +not be the innermost label enclosing the `break` expression, but must enclose +it. ## `continue` expressions @@ -639,12 +638,12 @@ A `continue` expression is only permitted in the body of a loop. ## `while` loops -A `while` loop begins by evaluating the boolean loop conditional expression. -If the loop conditional expression evaluates to `true`, the loop body block +A `while` loop begins by evaluating the boolean loop conditional expression. If +the loop conditional expression evaluates to `true`, the loop body block executes and control returns to the loop conditional expression. If the loop conditional expression evaluates to `false`, the `while` expression completes. -An example: + An example: ```rust let mut i = 0; @@ -657,8 +656,8 @@ while i < 10 { Like `loop` expressions, `while` loops can be controlled with `break` or `continue`, and may optionally have a _label_. See [infinite -loops](#infinite-loops), [break expressions](#break-expressions), and -[continue expressions](#continue-expressions) for more information. +loops](#infinite-loops), [break expressions](#break-expressions), and [continue +expressions](#continue-expressions) for more information. ## `for` expressions @@ -692,8 +691,8 @@ for i in 0..256 { Like `loop` expressions, `for` loops can be controlled with `break` or `continue`, and may optionally have a _label_. See [infinite -loops](#infinite-loops), [break expressions](#break-expressions), and -[continue expressions](#continue-expressions) for more information. +loops](#infinite-loops), [break expressions](#break-expressions), and [continue +expressions](#continue-expressions) for more information. ## `if` expressions @@ -794,8 +793,8 @@ let message = match x { ``` Range patterns only work on scalar types (like integers and characters; not -like arrays and structs, which have sub-components). A range pattern may not -be a sub-range of another range pattern inside the same `match`. +like arrays and structs, which have sub-components). A range pattern may not be +a sub-range of another range pattern inside the same `match`. Finally, match patterns can accept *pattern guards* to further refine the criteria for matching a case. Pattern guards appear after the pattern and From 2ca41c6d61570585cc447088af838bfac9c8fb4f Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 15:50:34 +0000 Subject: [PATCH 02/44] Clean up sections on methods and functions * Add examples for methods * Show the syntax for calling a struct field * Explain the function call syntax * Mention `Fn` traits * Move lambda section * Lambdas have unique types * `move` is part of the lambda expression according to libsyntax * Explain that `move` can extend the lifetime of the closure * Use closure, except when followed by 'expression' * Closure traits depend on how captures are used, not on how they are captured --- src/expressions.md | 144 +++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 63 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 269d42eaa4acd..288a4b820d4d0 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -220,17 +220,96 @@ 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.html#trait-objects). +```rust +let pi: Result = "3.14".parse(); +let log_pi = pi.unwrap_or(0.0).log(2.72); +# assert!(1.14 < log_pi && log_pi < 1.15) +``` + +## Call expressions + +A _call expression_ consists of an expression followed by a parenthesized +expression-list. It invokes a function, providing zero or more input variables. +If the function eventually returns, then the expression completes. The type of +the expression that is called must implement one of the `std::ops::Fn`, +`std::ops::FnMut` or `std::ops::FnOnce` traits, which differ in whether they +take the type by reference, mutable refernece, or take ownership respectively. +Some examples of call expressions: + +```rust +# fn add(x: i32, y: i32) -> i32 { 0 } +let three: i32 = add(1i32, 2i32); +let name: &'static str = (|| "Rust")(); +``` + +## Lambda expressions + +A _lambda expression_ (sometimes called an "anonymous function expression") +defines a closure and denotes it as a value, in a single expression. A lambda +expression is a pipe-symbol-delimited (`|`) list of patterns followed by an +expression. Type annotations may optionally be added for the type of the +parameters or for the return type. A lambda expession also may begin with the +`move` keyword before the initial `|`. + +A lambda expression denotes a function that maps a list of parameters +(`ident_list`) onto the expression that follows the `ident_list`. The +identifiers in the `ident_list` are the parameters to the function. If the +parameters' types are not be specified, then the compiler infers them from +context. Each closure expression has a unique anonymous type. + +Lambda expressions are most useful when passing functions as arguments to other +functions, as an abbreviation for defining and capturing a separate function. + +Significantly, lambda expressions _capture their environment_, which regular +[function definitions](items.html#functions) do not. Without the `move` +keyword, the lambda expression infers how it captures each variable from its +environment, prefering to capture by shared reference, effectively borrowing +all outer variables mentioned inside the closure's body. If needed the compiler +will infer that instead mutable references should be taken, or that the values +should be moved or copied (depending on their type) from the environment. A +closure can be forced to capture its environment by copying or moving values by +prefixing it with the `move` keyword. This is often used to ensure that the +closure's type is `'static`. + +The compiler will determine which of the [closure +traits](types.html#closure-types) the closure's type will implement by how it +acts on them. The closure will also implement [`Send`](the-send-trait.html) +and/or [`Sync`](the-sync-trait.html) if all of its captured types do. These +traits allow functions to accept closures using generics, even though the exact +types can't be named. + +In this example, we define a function `ten_times` that takes a higher-order +function argument, and we then call it with a lambda expression as an argument, +followed by a lambda expression that moves values from its environment. + +```rust +fn ten_times(f: F) where F: Fn(i32) { + for index in 0..10 { + f(index); + } +} + +ten_times(|j| println!("hello, {}", j)); + +let word = "konnichiwa".to_owned(); +ten_times(move |j| println!("{}, {}", word, j)); +``` + ## Field expressions A _field expression_ consists of an expression followed by a single dot and an identifier, when not immediately followed by a parenthesized expression-list -(the latter is a [method call expression](#method-call-expressions)). A field -expression denotes a field of a [struct](types.html#struct-types). +(the latter is always a [method call expression](#method-call-expressions)). A +field expression denotes a field of a [struct](types.html#struct-types). To +call a function stored in a struct parentheses are needed around the field +epression ```rust,ignore mystruct.myfield; foo().x; (Struct {a: 10, b: 20}).a; +mystruct.method(); // Method expression +(mystruct.function_field)() // Call expression ``` A field access is an [lvalue](expressions.html#lvalues-rvalues-and-temporaries) @@ -542,67 +621,6 @@ An example of a parenthesized expression: let x: i32 = (2 + 3) * 4; ``` - -## Call expressions - -A _call expression_ invokes a function, providing zero or more input variables -and an optional location to move the function's output into. If the function -eventually returns, then the expression completes. - -Some examples of call expressions: - -```rust -# fn add(x: i32, y: i32) -> i32 { 0 } - -let x: i32 = add(1i32, 2i32); -let pi: Result = "3.14".parse(); -``` - -## Lambda expressions - -A _lambda expression_ (sometimes called an "anonymous function expression") -defines a function and denotes it as a value, in a single expression. A lambda -expression is a pipe-symbol-delimited (`|`) list of identifiers followed by an -expression. - -A lambda expression denotes a function that maps a list of parameters -(`ident_list`) onto the expression that follows the `ident_list`. The -identifiers in the `ident_list` are the parameters to the function. These -parameters' types need not be specified, as the compiler infers them from -context. - -Lambda expressions are most useful when passing functions as arguments to other -functions, as an abbreviation for defining and capturing a separate function. - -Significantly, lambda expressions _capture their environment_, which regular -[function definitions](items.html#functions) do not. The exact type of capture -depends on the [function type](types.html#function-types) inferred for the -lambda expression. In the simplest and least-expensive form (analogous to a -```|| { }``` expression), the lambda expression captures its environment by -reference, effectively borrowing pointers to all outer variables mentioned -inside the function. Alternately, the compiler may infer that a lambda -expression should copy or move values (depending on their type) from the -environment into the lambda expression's captured environment. A lambda can be -forced to capture its environment by moving values by prefixing it with the -`move` keyword. - -In this example, we define a function `ten_times` that takes a higher-order -function argument, and we then call it with a lambda expression as an argument, -followed by a lambda expression that moves values from its environment. - -```rust -fn ten_times(f: F) where F: Fn(i32) { - for index in 0..10 { - f(index); - } -} - -ten_times(|j| println!("hello, {}", j)); - -let word = "konnichiwa".to_owned(); -ten_times(move |j| println!("{}, {}", word, j)); -``` - ## Infinite loops A `loop` expression denotes an infinite loop. From c993ff9e42f3fe000ffc74635e360b0452b615b3 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 15:52:50 +0000 Subject: [PATCH 03/44] Make 'identifier's into links. --- src/expressions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 288a4b820d4d0..d8876c712b999 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -128,7 +128,7 @@ There are several forms of struct expressions. A _struct expression_ consists of the [path](paths.html) of a [struct item](items.html#structs), followed by a brace-enclosed list of zero or more comma-separated name-value pairs, providing the field values of a new instance of the struct. A field name can be -any identifier, and is separated from its value expression by a colon. The +any [identifier](identifiers.html), and is separated from its value expression by a colon. The location denoted by a struct field is mutable if and only if the enclosing struct is mutable. @@ -214,7 +214,7 @@ assert_eq!(5, x); ## Method-call expressions A _method call_ consists of an expression followed by a single dot, an -identifier, and a parenthesized expression-list. Method calls are resolved to +[identifier](identifiers.html), and a parenthesized expression-list. Method calls are resolved to 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 @@ -298,7 +298,7 @@ ten_times(move |j| println!("{}, {}", word, j)); ## Field expressions A _field expression_ consists of an expression followed by a single dot and an -identifier, when not immediately followed by a parenthesized expression-list +[identifier](identifiers.html), when not immediately followed by a parenthesized expression-list (the latter is always a [method call expression](#method-call-expressions)). A field expression denotes a field of a [struct](types.html#struct-types). To call a function stored in a struct parentheses are needed around the field From e92490137e7ad308aa1b9c75ce1b789d66fc5238 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 15:56:20 +0000 Subject: [PATCH 04/44] Some more corrections to lambda expressions * Parameters are patterns, not idents. * Make it clear that inference can be done on just some of the parameters --- src/expressions.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index d8876c712b999..b39712a21669b 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -252,10 +252,10 @@ parameters or for the return type. A lambda expession also may begin with the `move` keyword before the initial `|`. A lambda expression denotes a function that maps a list of parameters -(`ident_list`) onto the expression that follows the `ident_list`. The -identifiers in the `ident_list` are the parameters to the function. If the -parameters' types are not be specified, then the compiler infers them from -context. Each closure expression has a unique anonymous type. +(`ident_list`) onto the expression that follows the `ident_list`. The patterns +in the `ident_list` are the parameters to the closure. If a parameter's types +is not specified, then the compiler infers it from context. Each closure +expression has a unique anonymous type. Lambda expressions are most useful when passing functions as arguments to other functions, as an abbreviation for defining and capturing a separate function. From f8b3af3b038ac192e17ee533cf0caa515aa79198 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 16:21:40 +0000 Subject: [PATCH 05/44] Expand and correct the array expressions section. * Explain what arrays expressions do. * `static`s aren't constant expressions. * Explain `Copy` requirement. --- src/expressions.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index b39712a21669b..3eebfa9e3c832 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -322,13 +322,19 @@ possible. In cases of ambiguity, we prefer fewer autoderefs to more. ## Array expressions -An [array](types.html#array-and-slice-types) _expression_ is written by +An [array](types.html#array-and-slice-types) _expression_ can be written by enclosing zero or more comma-separated expressions of uniform type in square -brackets. - -In the `[expr ';' expr]` form, the expression after the `';'` must be a -constant expression that can be evaluated at compile time, such as a -[literal](tokens.html#literals) or a [static item](items.html#static-items). +brackets. This produces and array containing each of these values in the +order they are written. + +Alternatively there can be exactly two expresions inside the brackets, +separated by a semi-colon. The expression after the `;` must be a have type +`usize` and be a constant expression that can be evaluated at compile time, +such as a [literal](tokens.html#literals) or a [constant item +item](items.html#constant-items). `[a; b]` creates an array containing `b` copies +of the value of `a`. If the expression after the semi-colon has a value +greater than 1 then this requires that the type of `a` is +[`Copy`](the-copy-trait.html). ```rust [1, 2, 3, 4]; From c2e67973588adb3209cc1cd35f35449e9dd584c6 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 18:37:33 +0000 Subject: [PATCH 06/44] Explain method call resolution --- src/expressions.md | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 3eebfa9e3c832..55ed2f568c2d7 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -214,11 +214,26 @@ assert_eq!(5, x); ## Method-call expressions A _method call_ consists of an expression followed by a single dot, an -[identifier](identifiers.html), and a parenthesized expression-list. Method calls are resolved to -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.html#trait-objects). +[identifier](identifiers.html), and a parenthesized expression-list. Method +calls are resolved to 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.html#trait-objects). If the method was defined to take `&self` or +`&mut self` then a borrow automatically be taken. + +When resolving method calls on an expression of type `A`, Rust will use the +following order: +1. Methods defined on `A`, with a `self`, `&self` or `&mut self` receiver. +1. Methods defined by traits, with receiver of type `A`. +1. Methods defined by traits, with receiver of type `&A`. +1. Methods defined by traits, with receiver of type `&mut A`. +1. If it's possible, Rust will then repeat steps 1-5 with + `::Target`, and insert a dereference operator. + +Note, in steps 2-4 the trait doesn't have to be implemented by `A`, for example +in step 3 the trait could be implemented for `&A` and with the method taking +`self`. If a step is reached where there is more than one possible method, then +it is a compiler error. To resolve this use THIS ISN'T IN THE REFERENCE!!!!!!!! ```rust let pi: Result = "3.14".parse(); From 710504802b101ee84c7c5670bef36df8ddc15994 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 18:38:48 +0000 Subject: [PATCH 07/44] Improve index expressions * Specify how overloading is done. * Indices must be of type `usize`. --- src/expressions.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 55ed2f568c2d7..74b272523ee3e 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -360,32 +360,32 @@ greater than 1 then this requires that the type of `a` is ## Index expressions -[Array](types.html#array-and-slice-types)-typed expressions can be indexed by -writing a square-bracket-enclosed expression (the index) after them. When the -array is mutable, the resulting +[Array and slice](types.html#array-and-slice-types)-typed expressions can be +indexed by writing a square-bracket-enclosed expression (the index) after them. +When the array is mutable, the resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be assigned to. +For other types an index expression `a[b]` is equivalent to `*a.index(b)`, or +`*a.index_mut(b)` when needed in a mutable context, where the methods are from +the traits `std::ops::Index` and `std::ops::IndexMut`. Just as with methods, +Rust will try to derefence `a` repeatedly until it finds an implementation. -Indices are zero-based, and may be of any integral type. Vector access is -bounds-checked at compile-time for constant arrays being accessed with a -constant index value. Otherwise a check will be performed at run-time that -will put the thread in a _panicked state_ if it fails. +Indices are zero-based, and are of type `usize` for arrays and slices. Vector +access is bounds-checked at compile-time for constant arrays being accessed +with aconstant index value. Otherwise a check will be performed at run-time +that will put the thread in a _panicked state_ if it fails. ```rust,should_panic -([1, 2, 3, 4])[0]; +([1, 2, 3, 4])[2]; // Evluates to 3 let x = (["a", "b"])[10]; // compiler error: const index-expr is out of bounds let n = 10; -let y = (["a", "b"])[n]; // panics +let y = (["a", "b"])[n]; // panics let arr = ["a", "b"]; -arr[10]; // panics +arr[10]; // panics ``` -Also, if the type of the expression to the left of the brackets is a pointer, -it is automatically dereferenced as many times as necessary to make the -indexing possible. In cases of ambiguity, we prefer fewer autoderefs to more. - ## Range expressions The `..` operator will construct an object of one of the `std::ops::Range` variants. From 29af6c49e7928baf8c1f7641be3fd8ed8b174035 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 19:01:00 +0000 Subject: [PATCH 08/44] Improve unary operators * Explained `std::ops::Neg`. * Hopefully made it clearer how `Deref` works * Explained `std::ops::Not`. * Say that `&mut` can't be applied to everything. --- src/expressions.md | 54 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 74b272523ee3e..8bba03b00bd61 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -29,12 +29,12 @@ expressions](#index-expressions) (`expr[expr]`), and [field references](#field-expressions) (`expr.f`). All other expressions are rvalues. The left operand of an [assignment](#assignment-expressions) or -[compound-assignment](#compound-assignment-expressions) expression is -an lvalue context, as is the single operand of a unary -[borrow](#unary-operator-expressions). The discriminant or subject of -a [match expression](#match-expressions) may be an lvalue context, if -ref bindings are made, but is otherwise an rvalue context. All other -expression contexts are rvalue contexts. +[compound-assignment](#compound-assignment-expressions) expression is an lvalue +context, as is the single operand of a unary +[borrow](#unary-operator-expressions). The discriminant or subject of a [match +expression](#match-expressions) may be an lvalue context, if ref bindings are +made, but is otherwise an rvalue context. All other expression contexts are +rvalue contexts. When an lvalue is evaluated in an _lvalue context_, it denotes a memory location; when evaluated in an _rvalue context_, it denotes the value held _in_ @@ -433,35 +433,35 @@ all written as prefix operators, before the expression they apply to. * `-` : Negation. Signed integer types and floating-point types support negation. It is an error to apply negation to unsigned types; for example, the compiler - rejects `-1u32`. + rejects `-1u32`. `-` can be overloaded for a type by implementing the + `std::ops::Neg` trait. * `*` : Dereference. When applied to a [pointer](types.html#pointer-types) it denotes the pointed-to location. For pointers to mutable locations, the resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be - assigned to. On non-pointer types, it calls the `deref` method of the - `std::ops::Deref` trait, or the `deref_mut` method of the - `std::ops::DerefMut` trait (if implemented by the type and required for an - outer expression that will or could mutate the dereference), and produces - the result of dereferencing the `&` or `&mut` borrowed pointer returned - from the overload method. + assigned to. Dereferencing a raw pointer requires `unsafe`. On non-pointer + types `*x` is equivalent to `*std::ops::Deref::deref(&x)` or + `*std::ops::Deref::deref_mut(&mut x)` depending on whether the rquired + lvalue has to be mutable. * `!` : Logical negation. On the boolean type, this flips between `true` and - `false`. On integer types, this inverts the individual bits in the - two's complement representation of the value. + `false`. On integer types, this inverts the individual bits of the binary + representation of the value, using two's complement for signed integers. + `!` can be overloaded for a type by implementing the `std::ops::Not` trait. * `&` and `&mut` - : Borrowing. When applied to an lvalue, these operators produce a - reference (pointer) to the lvalue. The lvalue is also placed into - a borrowed state for the duration of the reference. For a shared - borrow (`&`), this implies that the lvalue may not be mutated, but - it may be read or shared again. For a mutable borrow (`&mut`), the - lvalue may not be accessed in any way until the borrow expires. - If the `&` or `&mut` operators are applied to an rvalue, a - temporary value is created; the lifetime of this temporary value - is defined by [syntactic rules](#temporary-lifetimes). + : Borrowing. When applied to an lvalue, these operators produce a reference + (pointer) to the lvalue. The lvalue is also placed into a borrowed state + for the duration of the reference. For a shared borrow (`&`), this implies + that the lvalue may not be mutated, but it may be read or shared again. For + a mutable borrow (`&mut`), the lvalue may not be accessed in any way until + the borrow expires. If the `&` or `&mut` operators are applied to an + rvalue, a temporary value is created; the lifetime of this temporary value + is defined by [syntactic rules](#temporary-lifetimes). `&mut` may only be + applied to `lvalues` that can be mutated. * `?` - : Propagating errors if applied to `Err(_)` and unwrapping if - applied to `Ok(_)`. Only works on the `Result` type, - and written in postfix notation. + : Propagating errors if applied to `Err(_)` and unwrapping if applied to + `Ok(_)`. Only works on the `Result` type, and written in postfix + notation. ## Binary operator expressions From 4853a00208df48fc2d95c04e52c24d549638debd Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 19:02:43 +0000 Subject: [PATCH 09/44] More wrapping changes --- src/expressions.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 8bba03b00bd61..b5da8d64bfe06 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -29,12 +29,12 @@ expressions](#index-expressions) (`expr[expr]`), and [field references](#field-expressions) (`expr.f`). All other expressions are rvalues. The left operand of an [assignment](#assignment-expressions) or -[compound-assignment](#compound-assignment-expressions) expression is an lvalue -context, as is the single operand of a unary -[borrow](#unary-operator-expressions). The discriminant or subject of a [match -expression](#match-expressions) may be an lvalue context, if ref bindings are -made, but is otherwise an rvalue context. All other expression contexts are -rvalue contexts. +[compound-assignment](#compound-assignment-expressions) expression is +an lvalue context, as is the single operand of a unary +[borrow](#unary-operator-expressions). The discriminant or subject of +a [match expression](#match-expressions) may be an lvalue context, if +ref bindings are made, but is otherwise an rvalue context. All other +expression contexts are rvalue contexts. When an lvalue is evaluated in an _lvalue context_, it denotes a memory location; when evaluated in an _rvalue context_, it denotes the value held _in_ From 837b41fb10223bcf7cb68b603906cd63157472a3 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 19:03:51 +0000 Subject: [PATCH 10/44] Merge operators --- src/expressions.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index b5da8d64bfe06..1fe72b0d6734c 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -425,7 +425,9 @@ let y = 0...10; assert_eq!(x, y); ``` -## Unary operator expressions +## Operator expressions + +### Unary operator expressions Rust defines the following unary operators. With the exception of `?`, they are all written as prefix operators, before the expression they apply to. @@ -463,11 +465,6 @@ all written as prefix operators, before the expression they apply to. `Ok(_)`. Only works on the `Result` type, and written in postfix notation. -## Binary operator expressions - -Binary operators expressions are given in terms of [operator -precedence](#operator-precedence). - ### Arithmetic operators Binary arithmetic expressions are syntactic sugar for calls to built-in traits, From bcbba66b54ce56d0d828ba05cf870d90b4bbd9c1 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 19:40:43 +0000 Subject: [PATCH 11/44] Improve binary operators * Built in operators don't use traits. * Explain that the type of right shift depends on the type. --- src/expressions.md | 104 ++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 62 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 1fe72b0d6734c..22e054f4b1b46 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -427,6 +427,13 @@ assert_eq!(x, y); ## Operator expressions +Operators are defined for built in types by the Rust language. Operators will +panic when they overflow when compiled in debug mode. Many of the following +operators can be overloaded using traits in `std::ops` or `std::cmp`. Note that +the traits in `std::cmp` 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. + ### Unary operator expressions Rust defines the following unary operators. With the exception of `?`, they are @@ -459,59 +466,59 @@ all written as prefix operators, before the expression they apply to. the borrow expires. If the `&` or `&mut` operators are applied to an rvalue, a temporary value is created; the lifetime of this temporary value is defined by [syntactic rules](#temporary-lifetimes). `&mut` may only be - applied to `lvalues` that can be mutated. + applied to `lvalues` that can be mutated. These operators cannot be + overloaded. * `?` : Propagating errors if applied to `Err(_)` and unwrapping if applied to `Ok(_)`. Only works on the `Result` type, and written in postfix notation. -### Arithmetic operators +### Binary Operators Expressions -Binary arithmetic expressions are syntactic sugar for calls to built-in traits, -defined in the `std::ops` module of the `std` library. This means that -arithmetic operators can be overridden for user-defined types. The default -meaning of the operators on standard types is given here. +Binary operators expressions are all written with infix notation. * `+` - : Addition and array/string concatenation. - Calls the `add` method on the `std::ops::Add` trait. + : Addition. Overloaded by the `std::ops::Add` trait. * `-` - : Subtraction. - Calls the `sub` method on the `std::ops::Sub` trait. + : Subtraction. Overloaded by the `std::ops::Sub` trait. * `*` - : Multiplication. - Calls the `mul` method on the `std::ops::Mul` trait. + : Multiplication. Overloaded by the `std::ops::Mul` trait. * `/` - : Quotient. - Calls the `div` method on the `std::ops::Div` trait. + : Quotient. Overloaded by the `std::ops::Div` trait. * `%` - : Remainder. - Calls the `rem` method on the `std::ops::Rem` trait. - -### Bitwise operators - -Like the [arithmetic operators](#arithmetic-operators), bitwise operators are -syntactic sugar for calls to methods of built-in traits. This means that -bitwise operators can be overridden for user-defined types. The default -meaning of the operators on standard types is given here. Bitwise `&`, `|` and -`^` applied to boolean arguments are equivalent to logical `&&`, `||` and `!=` -evaluated in non-lazy fashion. - + : Remainder. Overloaded by the `std::ops::Rem` trait. * `&` - : Bitwise AND. - Calls the `bitand` method of the `std::ops::BitAnd` trait. + : Bitwise AND for integer for integer types, logical AND for `bool` which + always evaluates both operands. Overloaded by the `std::ops::BitAnd` trait. * `|` - : Bitwise inclusive OR. - Calls the `bitor` method of the `std::ops::BitOr` trait. + : Bitwise inclusive OR for integer types, logical OR for `bool` which always + evaluates both operands. Overloaded by the `std::ops::BitOr` trait. * `^` - : Bitwise exclusive OR. - Calls the `bitxor` method of the `std::ops::BitXor` trait. + : Bitwise exclusive OR, logical XOR for `bool`. Overloaded by the + `std::ops::BitXor` trait. * `<<` : Left shift. - Calls the `shl` method of the `std::ops::Shl` trait. + Overloaded by the `std::ops::Shl` trait. * `>>` - : Right shift (arithmetic). - Calls the `shr` method of the `std::ops::Shr` trait. + : Arithmetic Right shift for signed integers. Logical Right shift for + unsigned integers. Overloaded by the `std::ops::Shl` trait. +* `==` + : Equal to. Overloaded by the `eq` method on the `std::cmp::PartialEq` trait. +* `!=` + : Unequal to. Overloaded by the `ne` method on the `std::cmp::PartialEq` + trait. +* `<` + : Less than. Overloaded by the `lt` method on the `std::cmp::PartialOrd` + trait. +* `>` + : Greater than. Overloaded by the `gt` method on the `std::cmp::PartialOrd` + trait. +* `<=` + : Less than or equal. Overloaded by the `le` method on the + `std::cmp::PartialOrd` trait. +* `>=` + : Greater than or equal. Overloaded by the `ge` method on the + `std::cmp::PartialOrd` trait. ### Lazy boolean operators @@ -523,33 +530,6 @@ the expression. That is, `||` only evaluates its right-hand operand when the left-hand operand evaluates to `false`, and `&&` only when it evaluates to `true`. -### Comparison operators - -Comparison operators are, like the [arithmetic -operators](#arithmetic-operators), and [bitwise operators](#bitwise-operators), -syntactic sugar for calls to built-in traits. This means that comparison -operators can be overridden for user-defined types. The default meaning of the -operators on standard types is given here. - -* `==` - : Equal to. - Calls the `eq` method on the `std::cmp::PartialEq` trait. -* `!=` - : Unequal to. - Calls the `ne` method on the `std::cmp::PartialEq` trait. -* `<` - : Less than. - Calls the `lt` method on the `std::cmp::PartialOrd` trait. -* `>` - : Greater than. - Calls the `gt` method on the `std::cmp::PartialOrd` trait. -* `<=` - : Less than or equal. - Calls the `le` method on the `std::cmp::PartialOrd` trait. -* `>=` - : Greater than or equal. - Calls the `ge` method on the `std::cmp::PartialOrd` trait. - ### Type cast expressions A type cast expression is denoted with the binary operator `as`. From 5e4a95864cc58db009c8397ea367334f84ee3773 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 19:44:56 +0000 Subject: [PATCH 12/44] Remove an unnecessary new blank line in an example --- src/expressions.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/expressions.md b/src/expressions.md index 22e054f4b1b46..c35e0e4291769 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -542,7 +542,6 @@ An example of an `as` expression: ```rust # fn sum(values: &[f64]) -> f64 { 0.0 } # fn len(values: &[f64]) -> i32 { 0 } - fn average(values: &[f64]) -> f64 { let sum: f64 = sum(values); let size: f64 = len(values) as f64; From e091c57e7dfcc63ca8e6c338c37c500a9f745a88 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 19:49:21 +0000 Subject: [PATCH 13/44] Improve Compound assignments * Explain overloading --- src/expressions.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/expressions.md b/src/expressions.md index c35e0e4291769..12ed99a3edff4 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -578,8 +578,11 @@ x = y; The `+`, `-`, `*`, `/`, `%`, `&`, `|`, `^`, `<<`, and `>>` operators may be composed with the `=` operator. The expression `lval OP= val` is equivalent to `lval = lval OP val`. For example, `x = x + 1` may be written as `x += 1`. - Any such expression always has the [`unit`](types.html#tuple-types) type. +These operators can all be overloaded using the trait with the same name as for +the normal operation followed by 'Assign', for example, `std::ops::AddAssign` +is used to overload `+=`. + ### Operator precedence From a6048c3bf8c66e7aa813ec16285e2579d0e14b8c Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 20:20:27 +0000 Subject: [PATCH 14/44] Improve operator precedence. * Add unary operators * Show the correct associativity --- src/expressions.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 12ed99a3edff4..2374a58496f82 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -587,27 +587,27 @@ is used to overload `+=`. ### Operator precedence The precedence of Rust binary operators is ordered as follows, going from -strong to weak: - -```text -as : -* / % -+ - -<< >> -& -^ -| -== != < > <= >= -&& -|| -.. ... -<- -= -``` +strong to weak. Binary Operators at the same precedence level are evaluated +in the order given by their associativity. + +| Operator | Associativity | +|-----------------------------|-------------------------| +| `?` | | +| Unary `-` `*` `!` `&` `&mut` | | +| `as` `:` | Left to Right | +| `*` `/` `%` | Left to Right | +| `+` `-` | Left to Right | +| `<<` `>>` | Left to Right | +| `&` | Left to Right | +| `^` | Left to Right | +| | | Left to Right | +| `==` `!=` `<` `>` `<=` `>=` | Require parentheses | +| `&&` | Left to Right | +| || | Left to Right | +| `..` `...` | Require parentheses | +| `<-` | Right to Left | +| `=` `+=` `-=` `*=` `/=` `%=` `&=` |= `^=` `<<=` `>>=` | Right to Left | -Operators at the same precedence level are evaluated left-to-right. [Unary -operators](#unary-operator-expressions) have the same precedence level and are -stronger than any of the binary operators. ## Grouped expressions From 764da0e61e8714cdf9044991654b1cc9138873c4 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 20:38:49 +0000 Subject: [PATCH 15/44] Remove some unnecessary blank lines --- src/expressions.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 2374a58496f82..419891caadd43 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -690,7 +690,6 @@ An example of a `for` loop over the contents of an array: # let a = 0; # let b = 0; # let c = 0; - let v: &[Foo] = &[a, b, c]; for e in v { @@ -802,7 +801,6 @@ may be specified with `...`. For example: ```rust # let x = 2; - let message = match x { 0 | 1 => "not many", 2 ... 9 => "a few", @@ -823,7 +821,6 @@ may refer to the variables bound within the pattern they follow. # let maybe_digit = Some(0); # fn process_digit(i: i32) { } # fn process_other(i: i32) { } - let message = match maybe_digit { Some(x) if x < 10 => process_digit(x), Some(x) => process_other(x), From a57aeeaa28a8a99595256c321ee717b306590b61 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 20:45:58 +0000 Subject: [PATCH 16/44] Improve the example for grouped expressions --- src/expressions.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/expressions.md b/src/expressions.md index 419891caadd43..d4a4b6975e9f1 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -618,7 +618,10 @@ within an expression. An example of a parenthesized expression: ```rust -let x: i32 = (2 + 3) * 4; +let x: i32 = 2 + 3 * 4; +let y: i32 = (2 + 3) * 4; +assert_eq!(x, 14); +assert_eq!(y, 20); ``` ## Infinite loops From 056ffa62ab209f853ab70e66f51307bb99f34ef7 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 21:22:32 +0000 Subject: [PATCH 17/44] Simlify and clarify method call resolution --- src/expressions.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index d4a4b6975e9f1..03f1a1a1b4caf 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -223,17 +223,18 @@ object](types.html#trait-objects). If the method was defined to take `&self` or When resolving method calls on an expression of type `A`, Rust will use the following order: -1. Methods defined on `A`, with a `self`, `&self` or `&mut self` receiver. -1. Methods defined by traits, with receiver of type `A`. -1. Methods defined by traits, with receiver of type `&A`. -1. Methods defined by traits, with receiver of type `&mut A`. +1. Inherent methods, with receiver `A`, `&A`, `&mut A`. +1. Trait methods with receiver of type `A`. +1. Trait methods with receiver of type `&A`. +1. Trait methods with receiver of type `&mut A`. 1. If it's possible, Rust will then repeat steps 1-5 with `::Target`, and insert a dereference operator. -Note, in steps 2-4 the trait doesn't have to be implemented by `A`, for example -in step 3 the trait could be implemented for `&A` and with the method taking -`self`. If a step is reached where there is more than one possible method, then -it is a compiler error. To resolve this use THIS ISN'T IN THE REFERENCE!!!!!!!! +Note: in steps 1-4 the method doesn't have to be implemented on `A`. For +example in step 3 the trait could be implemented for `&A` with the method +taking `self`. If a step is reached where there is more than one possible +method, then it is a compiler error. To resolve this use THIS ISN'T IN THE +REFERENCE!!!!!!!! ```rust let pi: Result = "3.14".parse(); From f2ded24f711487f4cd0df82194e27a1e5f693aec Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 22:22:25 +0000 Subject: [PATCH 18/44] Use 'then' instead of 'and' for ordered events. --- src/expressions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 03f1a1a1b4caf..063ba47a5b9d2 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -662,7 +662,7 @@ A `continue` expression is only permitted in the body of a loop. A `while` loop begins by evaluating the boolean loop conditional expression. If the loop conditional expression evaluates to `true`, the loop body block -executes and control returns to the loop conditional expression. If the loop +executes, then control returns to the loop conditional expression. If the loop conditional expression evaluates to `false`, the `while` expression completes. An example: @@ -859,7 +859,7 @@ if let ("Ham", b) = dish { A `while let` loop is semantically identical to a `while` loop but in place of a condition expression it expects `let` statement with a refutable pattern. If the value of the expression on the right hand side of the `let` statement -matches the pattern, the loop body block executes and control returns to the +matches the pattern, the loop body block executes then control returns to the pattern matching statement. Otherwise, the while expression completes. ## `return` expressions From e4102a350a57d8c95496efafc9d9b3994548c192 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 13 Mar 2017 23:56:19 +0000 Subject: [PATCH 19/44] Improve loops and control flow * Use 'then' instead of and. * State that all loops return `()`. * Add some more examples. * Don't use 'identical' for things that aren't. * Make the definition of `if let` and `while let` clearer. * State that struct expressions can't be used in control flow expressions. --- src/expressions.md | 76 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 19 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 063ba47a5b9d2..c952c6364a562 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -126,11 +126,13 @@ comma: There are several forms of struct expressions. A _struct expression_ consists of the [path](paths.html) of a [struct item](items.html#structs), followed by a -brace-enclosed list of zero or more comma-separated name-value pairs, -providing the field values of a new instance of the struct. A field name can be -any [identifier](identifiers.html), and is separated from its value expression by a colon. The -location denoted by a struct field is mutable if and only if the enclosing -struct is mutable. +brace-enclosed list of zero or more comma-separated name-value pairs, providing +the field values of a new instance of the struct. A field name can be any +[identifier](identifiers.html), and is separated from its value expression by a +colon. The location denoted by a struct field is mutable if and only if the +enclosing struct is mutable. Struct expressions can't be used directly in the +head of an [`if`](#if-expressions), [`while`](#while-loops), +[`for`](#for-expressions) or [`match`](#match-expressions) expression. A _tuple struct expression_ consists of the [path](paths.html) of a [struct item](items.html#structs), followed by a parenthesized list of one or more @@ -634,7 +636,7 @@ lifetime preceding the loop expression, as in `'foo: loop{ }`. If a label is present, then labeled `break` and `continue` expressions nested within this loop may exit out of this loop or return control to its head. See [break expressions](#break-expressions) and [continue -expressions](#continue-expressions). +expressions](#continue-expressions). Any `loop` expression has value `()`. ## `break` expressions @@ -679,7 +681,8 @@ while i < 10 { Like `loop` expressions, `while` loops can be controlled with `break` or `continue`, and may optionally have a _label_. See [infinite loops](#infinite-loops), [break expressions](#break-expressions), and [continue -expressions](#continue-expressions) for more information. +expressions](#continue-expressions) for more information. Any `while` loop +expression has value `()`. ## `for` expressions @@ -713,7 +716,8 @@ for i in 0..256 { Like `loop` expressions, `for` loops can be controlled with `break` or `continue`, and may optionally have a _label_. See [infinite loops](#infinite-loops), [break expressions](#break-expressions), and [continue -expressions](#continue-expressions) for more information. +expressions](#continue-expressions) for more information. Like `loop` and +`while`, `for` loops evaluate to `()`. ## `if` expressions @@ -725,7 +729,27 @@ expression evaluates to `true`, the consequent block is executed and any subsequent `else if` or `else` block is skipped. If a condition expression evaluates to `false`, the consequent block is skipped and any subsequent `else if` condition is evaluated. If all `if` and `else if` conditions evaluate to -`false` then any `else` block is executed. +`false` then any `else` block is executed. An if expression evaluates to the +same value as the executed block, or `()` if no block is evaluated. An `if` +expression must have the same type in all situtaions. + +```rust +# let x = 3; +if x == 4 { + println!("x is four"); +} else if x == 3 { + println!("x is three"); +} else { + println!("x is something else"); +} + +let y = if 12 * 15 > 150 { + "Bigger" +} else { + "Smaller" +}; +assert_eq!(y, "Bigger"); +``` ## `match` expressions @@ -834,11 +858,13 @@ let message = match maybe_digit { ## `if let` expressions -An `if let` expression is semantically identical to an `if` expression but in -place of a condition expression it expects a `let` statement with a refutable -pattern. If the value of the expression on the right hand side of the `let` -statement matches the pattern, the corresponding block will execute, otherwise -flow proceeds to the first `else` block that follows. +An `if let` expression is semantically similar to an `if` expression but in +place of a condition expression it expects the keyword `let` followed by a +refutable pattern, an `=` and an expression. If the value of the expression on +the right hand side of the `=` matches the pattern, the corresponding block +will execute, otherwise flow proceeds to the following `else` block if it +exists. Like `if` expressions, `if let` expressions have a value determined by +the block that is evaluated. ```rust let dish = ("Ham", "Eggs"); @@ -846,6 +872,9 @@ let dish = ("Ham", "Eggs"); // this body will be skipped because the pattern is refuted if let ("Bacon", b) = dish { println!("Bacon is served with {}", b); +} else { + // This block is evaluated instead. + println!("No bacon will be served"); } // this body will execute @@ -856,11 +885,20 @@ if let ("Ham", b) = dish { ## `while let` loops -A `while let` loop is semantically identical to a `while` loop but in place of -a condition expression it expects `let` statement with a refutable pattern. If -the value of the expression on the right hand side of the `let` statement -matches the pattern, the loop body block executes then control returns to the -pattern matching statement. Otherwise, the while expression completes. +A `while let` loop is semantically similar to a `while` loop but in place of a +condition expression it expects the keyword `let` followed by a refutable +pattern, an `=` and an expression. If the value of the expression on the right +hand side of the `=` matches the pattern, the loop body block executes then +control returns to the pattern matching statement. Otherwise, the while +expression completes. Like `while` loops, `while let` loops evaluate to `()`. + +```rust +let x = vec![1, 2, 3]; + +while let Some(y) = x.pop() { + println!("y = {}"); +} +``` ## `return` expressions From d72c1884c7f78f109b1b26a79e012360fc08392b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 14 Mar 2017 19:27:27 +0000 Subject: [PATCH 20/44] Move field expressions next to Methods --- src/expressions.md | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index c952c6364a562..70a000dc8ea05 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -244,6 +244,31 @@ let log_pi = pi.unwrap_or(0.0).log(2.72); # assert!(1.14 < log_pi && log_pi < 1.15) ``` +## Field expressions + +A _field expression_ consists of an expression followed by a single dot and an +[identifier](identifiers.html), when not immediately followed by a parenthesized expression-list +(the latter is always a [method call expression](#method-call-expressions)). A +field expression denotes a field of a [struct](types.html#struct-types). To +call a function stored in a struct parentheses are needed around the field +epression + +```rust,ignore +mystruct.myfield; +foo().x; +(Struct {a: 10, b: 20}).a; +mystruct.method(); // Method expression +(mystruct.function_field)() // Call expression +``` + +A field access is an [lvalue](expressions.html#lvalues-rvalues-and-temporaries) +referring to the value of that field. When the type providing the field +inherits mutability, it can be [assigned](#assignment-expressions) to. + +Also, if the type of the expression to the left of the dot is a pointer, it is +automatically dereferenced as many times as necessary to make the field access +possible. In cases of ambiguity, we prefer fewer autoderefs to more. + ## Call expressions A _call expression_ consists of an expression followed by a parenthesized @@ -313,31 +338,6 @@ let word = "konnichiwa".to_owned(); ten_times(move |j| println!("{}, {}", word, j)); ``` -## Field expressions - -A _field expression_ consists of an expression followed by a single dot and an -[identifier](identifiers.html), when not immediately followed by a parenthesized expression-list -(the latter is always a [method call expression](#method-call-expressions)). A -field expression denotes a field of a [struct](types.html#struct-types). To -call a function stored in a struct parentheses are needed around the field -epression - -```rust,ignore -mystruct.myfield; -foo().x; -(Struct {a: 10, b: 20}).a; -mystruct.method(); // Method expression -(mystruct.function_field)() // Call expression -``` - -A field access is an [lvalue](expressions.html#lvalues-rvalues-and-temporaries) -referring to the value of that field. When the type providing the field -inherits mutability, it can be [assigned](#assignment-expressions) to. - -Also, if the type of the expression to the left of the dot is a pointer, it is -automatically dereferenced as many times as necessary to make the field access -possible. In cases of ambiguity, we prefer fewer autoderefs to more. - ## Array expressions An [array](types.html#array-and-slice-types) _expression_ can be written by From ed91f13c95ea056a34f3352f4ca88e75209d9bc1 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 15 Mar 2017 14:56:21 +0000 Subject: [PATCH 21/44] Make operator tables Add operator examples Mention `if let` and `while let` as more places where struct literals can't be used. --- src/expressions.md | 109 +++++++++++++++++++++++++++------------------ 1 file changed, 65 insertions(+), 44 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 70a000dc8ea05..98e83c8c0f1e9 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -132,7 +132,8 @@ the field values of a new instance of the struct. A field name can be any colon. The location denoted by a struct field is mutable if and only if the enclosing struct is mutable. Struct expressions can't be used directly in the head of an [`if`](#if-expressions), [`while`](#while-loops), -[`for`](#for-expressions) or [`match`](#match-expressions) expression. +[`match`](#match-expressions), [`for`](#for-expressions), [`if +let`](#if-let-expressions) or [`while let`](#while-let-loops) expression. A _tuple struct expression_ consists of the [path](paths.html) of a [struct item](items.html#structs), followed by a parenthesized list of one or more @@ -476,52 +477,72 @@ all written as prefix operators, before the expression they apply to. `Ok(_)`. Only works on the `Result` type, and written in postfix notation. +```rust +let x = 6; +assert_eq!(-x, -6); +let y = &x; +assert_eq!(*y, 6); +assert_eq!(!x, -7); +``` + ### Binary Operators Expressions -Binary operators expressions are all written with infix notation. +Binary operators expressions are all written with infix notation. This table +summarizes the behaivour of arithmetic and logical operators on primitive types +and which traits are used to overload these operators for other types. Remember +that signed integers are always represented using two's complement. + +| Symbol | Integer | `bool` | Floating Point | Overloading Trait | +|--------|-------------------------|-------------|----------------|--------------------| +| `+` | Addition | | Addition | `std::ops::Add` | +| `-` | Subtraction | | Subtraction | `std::ops::Sub` | +| `*` | Multiplication | | Multiplication | `std::ops::Mul` | +| `/` | Division | | Division | `std::ops::Div` | +| `%` | Remainder | | Remainder | `std::ops::Rem` | +| `&` | Bitwise AND | Logical AND | | `std::ops::BitAnd` | +| | | Bitwise OR | Logical OR | | `std::ops::BitOr` | +| `^` | Bitwise XOR | Logical XOR | | `std::ops::BitXor` | +| `<<` | Left Shift | | | `std::ops::Shl` | +| `>>` | Right Shift* | | | `std::ops::Shr` | + +\* Arithmetic right shift on signed integers, Logical right shift on unsigned integers. + + +Comparison operators are also defined both for primitive types and many type in +the standard library. Unlike arithemetic and logical operators, the traits for +overloading the operators the traits for these operators require that they are +implemented to define actual comparisons. Many functions and macros in the +standard library can then use that assumption (although not to ensure safety). + +| Symbol | Meaning | Overloading method | +|--------|--------------------------|----------------------------| +| `==` | Equal | `std::cmp::PartialEq::eq` | +| `!=` | Not equal | `std::cmp::PartialEq::ne` | +| `>` | Greater than | `std::cmp::PartialOrd::gt` | +| `<` | Less than | `std::cmp::PartialOrd::lt` | +| `>=` | Greater than or equal to | `std::cmp::PartialOrd::ge` | +| `<=` | Less than or equal to | `std::cmp::PartialOrd::le` | + +Here is an example of all of these operators being used. -* `+` - : Addition. Overloaded by the `std::ops::Add` trait. -* `-` - : Subtraction. Overloaded by the `std::ops::Sub` trait. -* `*` - : Multiplication. Overloaded by the `std::ops::Mul` trait. -* `/` - : Quotient. Overloaded by the `std::ops::Div` trait. -* `%` - : Remainder. Overloaded by the `std::ops::Rem` trait. -* `&` - : Bitwise AND for integer for integer types, logical AND for `bool` which - always evaluates both operands. Overloaded by the `std::ops::BitAnd` trait. -* `|` - : Bitwise inclusive OR for integer types, logical OR for `bool` which always - evaluates both operands. Overloaded by the `std::ops::BitOr` trait. -* `^` - : Bitwise exclusive OR, logical XOR for `bool`. Overloaded by the - `std::ops::BitXor` trait. -* `<<` - : Left shift. - Overloaded by the `std::ops::Shl` trait. -* `>>` - : Arithmetic Right shift for signed integers. Logical Right shift for - unsigned integers. Overloaded by the `std::ops::Shl` trait. -* `==` - : Equal to. Overloaded by the `eq` method on the `std::cmp::PartialEq` trait. -* `!=` - : Unequal to. Overloaded by the `ne` method on the `std::cmp::PartialEq` - trait. -* `<` - : Less than. Overloaded by the `lt` method on the `std::cmp::PartialOrd` - trait. -* `>` - : Greater than. Overloaded by the `gt` method on the `std::cmp::PartialOrd` - trait. -* `<=` - : Less than or equal. Overloaded by the `le` method on the - `std::cmp::PartialOrd` trait. -* `>=` - : Greater than or equal. Overloaded by the `ge` method on the - `std::cmp::PartialOrd` trait. +```rust +assert_eq!(3 + 6, 9); +assert_eq!(5.5 - 1.25, 4.25); +assert_eq!(-5 * 14, -70); +assert_eq!(14 / 3, 4); +assert_eq!(100 % 7, 2); +assert_eq!(0b1010 & 0b1100, 0b1000); +assert_eq!(0b1010 | 0b1100, 0b1110); +assert_eq!(0b1010 ^ 0b1100, 0b110); +assert_eq!(13 << 3, 104); +assert_eq!(-10 >> 2, -3); +assert!(123 == 123); +assert!(23 != -12); +assert!(12.5 > 12.2); +assert!([1, 2, 3] < [1, 3, 4]); +assert!('A' <= 'B'); +assert!("World" >= "Hello"); +``` ### Lazy boolean operators From 0e119ee7fba2923f90b74c023df5ad4aa7c6f74e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Wed, 15 Mar 2017 15:14:44 +0000 Subject: [PATCH 22/44] Add another example, fix a typo. --- src/expressions.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 98e83c8c0f1e9..2fcb04c62aafe 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -554,6 +554,11 @@ the expression. That is, `||` only evaluates its right-hand operand when the left-hand operand evaluates to `false`, and `&&` only when it evaluates to `true`. +```rust +let x = false || true; // true +let y = false && panic!(); // false, doesn't evaluate `panic!()` +``` + ### Type cast expressions A type cast expression is denoted with the binary operator `as`. @@ -607,12 +612,18 @@ These operators can all be overloaded using the trait with the same name as for the normal operation followed by 'Assign', for example, `std::ops::AddAssign` is used to overload `+=`. +```rust +let mut x = 10; +x += 4; +assert_eq!(x, 14); +``` + ### Operator precedence -The precedence of Rust binary operators is ordered as follows, going from -strong to weak. Binary Operators at the same precedence level are evaluated -in the order given by their associativity. +The precedence of Rust operators is ordered as follows, going from strong to +weak. Binary Operators at the same precedence level are evaluated in the order +given by their associativity. | Operator | Associativity | |-----------------------------|-------------------------| From 6403330338838c8cf818b02290bdd2d32f5d36cb Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 17 Mar 2017 12:22:33 +0000 Subject: [PATCH 23/44] Fix `while let` example. --- src/expressions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 2fcb04c62aafe..098d82364d4d0 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -925,10 +925,10 @@ control returns to the pattern matching statement. Otherwise, the while expression completes. Like `while` loops, `while let` loops evaluate to `()`. ```rust -let x = vec![1, 2, 3]; +let mut x = vec![1, 2, 3]; while let Some(y) = x.pop() { - println!("y = {}"); + println!("y = {}", y); } ``` From ffecb50263418d9110ff4621c940865f849e1547 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 20 Mar 2017 14:05:24 +0000 Subject: [PATCH 24/44] More rvalue and lvalue stuff --- src/expressions.md | 225 ++++++++++++++++++++++++++++----------------- 1 file changed, 142 insertions(+), 83 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 098d82364d4d0..bab04fa964c96 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -15,7 +15,7 @@ In this way, the structure of expressions dictates the structure of execution. Blocks are just another kind of expression, so blocks, statements, expressions, and blocks again can recursively nest inside each other to an arbitrary depth. -### Lvalues, rvalues and temporaries +## Lvalues and rvalues Expressions are divided into two main categories: _lvalues_ and _rvalues_. Likewise within each expression, sub-expressions may occur in _lvalue context_ @@ -23,26 +23,38 @@ or _rvalue context_. The evaluation of an expression depends both on its own category and the context it occurs within. An lvalue is an expression that represents a memory location. These expressions -are [paths](#path-expressions) (which refer to local variables, function and -method arguments, or static variables), dereferences (`*expr`), [indexing -expressions](#index-expressions) (`expr[expr]`), and [field -references](#field-expressions) (`expr.f`). All other expressions are rvalues. +are [paths](#path-expressions) which refer to local variables, function and +method arguments, or static variables, +[dereferences](#the-dereference-operator) (`*expr`), [indexing +expressions](#index-expressions) (`expr[expr]`), [field +references](#field-expressions) (`expr.f`) and parenthesized lvalue +expressions. All other expressions are rvalues. The left operand of an [assignment](#assignment-expressions) or -[compound-assignment](#compound-assignment-expressions) expression is -an lvalue context, as is the single operand of a unary -[borrow](#unary-operator-expressions). The discriminant or subject of -a [match expression](#match-expressions) may be an lvalue context, if -ref bindings are made, but is otherwise an rvalue context. All other -expression contexts are rvalue contexts. +[compound-assignment](#compound-assignment-expressions) expression is an lvalue +context, as is the single operand of a unary [borrow](#borrow-operators), and +the operand of any implicit borrow. The discriminant or subject of a [match +expression](#match-expressions) may be an lvalue context, if ref bindings are +made, but is otherwise an rvalue context. All other expression contexts are +rvalue contexts. -When an lvalue is evaluated in an _lvalue context_, it denotes a memory -location; when evaluated in an _rvalue context_, it denotes the value held _in_ -that memory location. - -#### Temporary lifetimes +### Moved and copied types -When an rvalue is used in an lvalue context, a temporary un-named lvalue is +When an lvalue is evaluated in an _rvalue context_, it denotes the value held +_in_ that memory location. If value is of a type that implements `Copy`, then +the value will be copied. In other situations then if the type of the value is +[`Sized`](the-sized-trait.html) and then it may be possible to move the value. +Only the following lvalues may be moved out of: +* Local varables which are not currently borrowed. +* The result of dereferencing an expression of type `Box` which can also be moved out of. +* Fields of an lvalue which can be moved out of. +Moving out of an lvalue deinitialises that location, so that it can't be read +from again. In all other cases, trying to use an lvalue in an rvalue context is +an error. + +### Temporary lifetimes + +When using an rvalue in most lvalue contexts, a temporary un-named lvalue is created and used instead. The lifetime of temporary values is typically the innermost enclosing statement; the tail expression of a block is considered part of the statement that encloses the block. @@ -78,12 +90,6 @@ Here are some examples: - `let ref x = temp()`. In this case, the temporary is created using a ref binding, but the result is the same: the lifetime is extended to the enclosing block. -### Moved and copied types - -When a [local variable](variables.html) is used as an -[rvalue](expressions.html#lvalues-rvalues-and-temporaries), the variable will -be copied if its type implements `Copy`. All others are moved. - ## Literal expressions A _literal expression_ consists of one of the [literal](tokens.html#literals) @@ -100,8 +106,9 @@ boolean value, or the unit value. ## Path expressions A [path](paths.html) used as an expression context denotes either a local -variable or an item. Path expressions are -[lvalues](expressions.html#lvalues-rvalues-and-temporaries). +variable or an item. Path expressions that resolve to local or static +variables are [lvalues](expressions.html#lvalues-rvalues-and-temporaries). +Other paths are rvalues. ## Tuple expressions @@ -221,12 +228,12 @@ A _method call_ consists of an expression followed by a single dot, an calls are resolved to 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.html#trait-objects). If the method was defined to take `&self` or -`&mut self` then a borrow automatically be taken. +object](types.html#trait-objects). Method call expressions will automatically +take a shared or mutable borrow of the reciever if needed. When resolving method calls on an expression of type `A`, Rust will use the following order: -1. Inherent methods, with receiver `A`, `&A`, `&mut A`. +1. Inherent methods, with receiver or type `A`, `&A`, `&mut A`. 1. Trait methods with receiver of type `A`. 1. Trait methods with receiver of type `&A`. 1. Trait methods with receiver of type `&mut A`. @@ -274,11 +281,13 @@ possible. In cases of ambiguity, we prefer fewer autoderefs to more. A _call expression_ consists of an expression followed by a parenthesized expression-list. It invokes a function, providing zero or more input variables. -If the function eventually returns, then the expression completes. The type of -the expression that is called must implement one of the `std::ops::Fn`, -`std::ops::FnMut` or `std::ops::FnOnce` traits, which differ in whether they -take the type by reference, mutable refernece, or take ownership respectively. -Some examples of call expressions: +If the function eventually returns, then the expression completes. For +[non-function types](types.html#function-types), the expression f(...) uses the +method on one of the `std::ops::Fn`, `std::ops::FnMut` or `std::ops::FnOnce` +traits, which differ in whether they take the type by reference, mutable +refernece, or take ownership respectively. An automatic borrow will be taken if +needed. Rust will also automatically dereference `f` as required. Some examples +of call expressions: ```rust # fn add(x: i32, y: i32) -> i32 { 0 } @@ -368,10 +377,11 @@ greater than 1 then this requires that the type of `a` is indexed by writing a square-bracket-enclosed expression (the index) after them. When the array is mutable, the resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be assigned to. -For other types an index expression `a[b]` is equivalent to `*a.index(b)`, or -`*a.index_mut(b)` when needed in a mutable context, where the methods are from -the traits `std::ops::Index` and `std::ops::IndexMut`. Just as with methods, -Rust will try to derefence `a` repeatedly until it finds an implementation. +For other types an index expression `a[b]` is equivalent to +`*std::ops::Index::index(&a, b)`, or `*std::opsIndexMut::index_mut(&mut a, b)` +when needed in a mutable context (these traits also exist in `core::ops`). Just +as with methods, Rust will also insert dereference operations on `a` repeatedly +until it finds an implementation. Indices are zero-based, and are of type `usize` for arrays and slices. Vector access is bounds-checked at compile-time for constant arrays being accessed @@ -438,59 +448,104 @@ the traits in `std::cmp` 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. -### Unary operator expressions - -Rust defines the following unary operators. With the exception of `?`, they are -all written as prefix operators, before the expression they apply to. - -* `-` - : Negation. Signed integer types and floating-point types support negation. It - is an error to apply negation to unsigned types; for example, the compiler - rejects `-1u32`. `-` can be overloaded for a type by implementing the - `std::ops::Neg` trait. -* `*` - : Dereference. When applied to a [pointer](types.html#pointer-types) it - denotes the pointed-to location. For pointers to mutable locations, the - resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be - assigned to. Dereferencing a raw pointer requires `unsafe`. On non-pointer - types `*x` is equivalent to `*std::ops::Deref::deref(&x)` or - `*std::ops::Deref::deref_mut(&mut x)` depending on whether the rquired - lvalue has to be mutable. -* `!` - : Logical negation. On the boolean type, this flips between `true` and - `false`. On integer types, this inverts the individual bits of the binary - representation of the value, using two's complement for signed integers. - `!` can be overloaded for a type by implementing the `std::ops::Not` trait. -* `&` and `&mut` - : Borrowing. When applied to an lvalue, these operators produce a reference - (pointer) to the lvalue. The lvalue is also placed into a borrowed state - for the duration of the reference. For a shared borrow (`&`), this implies - that the lvalue may not be mutated, but it may be read or shared again. For - a mutable borrow (`&mut`), the lvalue may not be accessed in any way until - the borrow expires. If the `&` or `&mut` operators are applied to an - rvalue, a temporary value is created; the lifetime of this temporary value - is defined by [syntactic rules](#temporary-lifetimes). `&mut` may only be - applied to `lvalues` that can be mutated. These operators cannot be - overloaded. -* `?` - : Propagating errors if applied to `Err(_)` and unwrapping if applied to - `Ok(_)`. Only works on the `Result` type, and written in postfix - notation. +### Borrow operators + +The `&` and `&mut` operators are unary prefix operators. When applied to an +lvalue produce a reference (pointer) to the location that the value refers to. +The lvalue is also placed into a borrowed state for the duration of the +reference. For a shared borrow (`&`), this implies that the lvalue may not be +mutated, but it may be read or shared again. For a mutable borrow (`&mut`), the +lvalue may not be accessed in any way until the borrow expires. `&mut` may only +be applied to `lvalues` that can be mutated. If the `&` or `&mut` operators are +applied to an rvalue, a temporary value is created; the lifetime of this +temporary value is defined by [syntactic rules](#temporary-lifetimes). These +operators cannot be overloaded. + +```rust +{ + // a temporary with value 7 is created that lasts for this scope. + let shared_reference = &7; +} +let mut array = [-2, 3, 9]; +{ + // Mutably borrows `array` for this scope. + // `array` may only be used through `mutable_reference`. + let mutable_reference = &mut array; +} +``` + +### The dereference operator + +When the `*` (dereference) operator is also a unary prefix operator applied to +a [pointer](types.html#pointer-types) it denotes the pointed-to location. If +the expression is of type `&mut T` and `*mut T`, and is either a local +variable, a (nested) field of a local varaince or is a mutable lvalue, then the +resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be +assigned to. Dereferencing a raw pointer requires `unsafe`. + +On non-pointer types `*x` is equivalent to `*std::ops::Deref::deref(&x)` or +`*std::ops::Deref::deref_mut(&mut x)` depending on whether the rquired lvalue +has to be mutable. + +```rust +let x = &7; +assert_eq!(*x, 7); +let y = &mut 9; +*y = 11; +assert_eq!(*y, 11); +``` + +### The `?` operator. + +The `?` operator can be applied to values of the `Result` type to +propogate errors. If applied to `Err(e)` it will return `Err(From::from(e))` +from the enclosing function or closure. If applied to `Ok(x)` it will unwrap +the value to return `x`. Unlike other unary operators `?` is written in postfix +notation. `?` cannot be overloaded. + +```rust +# use std::num::ParseIntError; +fn try_to_parse() -> Result { + let x: i32 = "123".parse()?; // x = 123 + let y: i32 = "24a".parse()?; // returns an Err() immediately + Ok(x + y) // Doesn't run. +} + +let res = try_to_parse(); +println!("{:?}", res); +# assert!(res.is_err()) +``` + +### Other prefix unary operators + +This table summarizes the behaivour of the last two unary operators on +primitive types and which traits are used to overload these operators for other +types. Remember that signed integers are always represented using two's +complement. The operands of all of these operators are evaluated in rvalue +context and are moved or copied. + +| Symbol | Integer | `bool` | Floating Point | Overloading Trait | +|--------|-------------|-------------|----------------|--------------------| +| `-` | Negation | | Negation | `std::ops::Neg` | +| `!` | Bitwise NOT | Logical NOT | | `std::ops::Not` | + +Here are some example of these operators ```rust let x = 6; assert_eq!(-x, -6); -let y = &x; -assert_eq!(*y, 6); assert_eq!(!x, -7); +assert_eq!(true, !false); ``` ### Binary Operators Expressions Binary operators expressions are all written with infix notation. This table -summarizes the behaivour of arithmetic and logical operators on primitive types -and which traits are used to overload these operators for other types. Remember -that signed integers are always represented using two's complement. +summarizes the behaivour of arithmetic and logical binary operators on +primitive types and which traits are used to overload these operators for other +types. Remember that signed integers are always represented using two's +complement. The operands of all of these operators are evaluated in rvalue +context and are moved or copied. | Symbol | Integer | `bool` | Floating Point | Overloading Trait | |--------|-------------------------|-------------|----------------|--------------------| @@ -505,7 +560,7 @@ that signed integers are always represented using two's complement. | `<<` | Left Shift | | | `std::ops::Shl` | | `>>` | Right Shift* | | | `std::ops::Shr` | -\* Arithmetic right shift on signed integers, Logical right shift on unsigned integers. +\* Arithmetic right shift on signed integers, logical right shift on unsigned integers. Comparison operators are also defined both for primitive types and many type in @@ -513,6 +568,9 @@ the standard library. Unlike arithemetic and logical operators, the traits for overloading the operators the traits for these operators require that they are implemented to define actual comparisons. Many functions and macros in the standard library can then use that assumption (although not to ensure safety). +Unlike the arithmetic and logical operators above, these operators implicitly +take shared borrows of their operands, evaluating them in lvalue context. This +means that the operands don't have to be sized. | Symbol | Meaning | Overloading method | |--------|--------------------------|----------------------------| @@ -594,7 +652,8 @@ by an equals sign (`=`) and an Evaluating an assignment expression [either copies or moves](#moved-and-copied-types) its right-hand operand to its left-hand -operand. +operand. The left-hand operand must be an lvalue: using an rvalue results in a +compiler error, rather than promoting it to a temporary. ```rust # let mut x = 0; @@ -610,7 +669,7 @@ composed with the `=` operator. The expression `lval OP= val` is equivalent to Any such expression always has the [`unit`](types.html#tuple-types) type. These operators can all be overloaded using the trait with the same name as for the normal operation followed by 'Assign', for example, `std::ops::AddAssign` -is used to overload `+=`. +is used to overload `+=`. As with `=`, `lval` must be an lvalue. ```rust let mut x = 10; From 36789c01a6677210c6c095bcd6fb29e0e7746ce4 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Mar 2017 00:19:29 +0000 Subject: [PATCH 25/44] Get most of the potential content in place * Mutable lvalues * Implicit borrows * Overflow --- src/expressions.md | 226 ++++++++++++++++++++++++++++++--------------- 1 file changed, 149 insertions(+), 77 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index bab04fa964c96..8203628218f81 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -33,10 +33,10 @@ expressions. All other expressions are rvalues. The left operand of an [assignment](#assignment-expressions) or [compound-assignment](#compound-assignment-expressions) expression is an lvalue context, as is the single operand of a unary [borrow](#borrow-operators), and -the operand of any implicit borrow. The discriminant or subject of a [match -expression](#match-expressions) may be an lvalue context, if ref bindings are -made, but is otherwise an rvalue context. All other expression contexts are -rvalue contexts. +the operand of any [implicit borrow](#implicit-borrows). The discriminant or +subject of a [match expression](#match-expressions) and right side of a `let` +binding may be an lvalue context, if ref bindings are made, but is otherwise an +rvalue context. All other expression contexts are rvalue contexts. ### Moved and copied types @@ -45,12 +45,39 @@ _in_ that memory location. If value is of a type that implements `Copy`, then the value will be copied. In other situations then if the type of the value is [`Sized`](the-sized-trait.html) and then it may be possible to move the value. Only the following lvalues may be moved out of: -* Local varables which are not currently borrowed. -* The result of dereferencing an expression of type `Box` which can also be moved out of. -* Fields of an lvalue which can be moved out of. -Moving out of an lvalue deinitialises that location, so that it can't be read -from again. In all other cases, trying to use an lvalue in an rvalue context is -an error. +* [Variables](#variables.html) which are not currently borrowed. +* [Temporary values](#temporary-lifetimes). +* [Fields](#field-expressions) of an lvalue which can be moved out of and + doesn't implement [`Drop`](#the-drop-trait). +* The result of [dereferencing](#the-dereference-operator) an expression with + type `Box` and that can also be moved out of. + +Moving out of an lvalue deinitialises that location (if it comes from a local +vairable), so that it can't be read from again. In all other cases, trying to +use an lvalue in an rvalue context is an error. + +### Mutability + +For an lvalue to be [assigned](#assignment-expressions) to, [mutably +borrowed](#borrow-operators), [implicitly mutably borrowed](#implicit-borrows) +or bound to a pattern containing `ref mut` it must be _mutable_, we call these +contexts _mutable_ lvalue contexts, other lvalue contexts are called +_immutable_. + +The following expressions can create mutable lvalues: +* Mutable [variables](#variables.html), which are not currently borrowed. +* Mutable `static` items. +* [Temporary values](#temporary-lifetimes) +* [Fields](#field-expressions), this evaluates the expression in a mutable + lvalue context. +* [Dereferenes](#the-dereference-operator) of a `*mut T` pointer. +* Dereference of a variable, or field of a variable, with type `&mut T`. Note: + this is an exception to the next rule. +* Dereferences of a type that implements `DerefMut`, this then requires that + the value being derefenced is evalutated is a mutable lvalue context. +* [Indexing](#index-expressions) of a type that implements `DerefMut`, this + then evalutes the value being indexed (but not the index) in mutable lvalue + context. ### Temporary lifetimes @@ -90,6 +117,30 @@ Here are some examples: - `let ref x = temp()`. In this case, the temporary is created using a ref binding, but the result is the same: the lifetime is extended to the enclosing block. +### Implicit Borrows + +Certain expressions will treat an expression as an lvalue by implicitly +borrowing it. For example, it is possible to compare two unsized +[slices](#array-and-slice-types) for equality direcly, because the `==` +operator implicitly borrows it's operands: + +```rust +let a: &[i32] = &[1, 2, 3]; +let b: &[i32] = &vec![1, 2, 3]; +*a == *b; +/// Equivalent form: +::std::cmp::PartialEq::eq(&*a, &*b); +``` + +Implicit borrows may be taken in the following expressions: +* Left operand in [method-call expressions](#method-call-expressions) +* Left operand in [field expressions](#field-expressions) +* Left operand in [call expressions](#call-expressions) +* Left operand in [index expressions](#index-expressions) +* Operand of the [dereference](#the-dereference-operator) (`*`) operator +* Operands of [comparison operators](#comparison-operators) +* Left operands of the [compound assignment](#compound-assignment-expressions) + ## Literal expressions A _literal expression_ consists of one of the [literal](tokens.html#literals) @@ -106,9 +157,19 @@ boolean value, or the unit value. ## Path expressions A [path](paths.html) used as an expression context denotes either a local -variable or an item. Path expressions that resolve to local or static -variables are [lvalues](expressions.html#lvalues-rvalues-and-temporaries). -Other paths are rvalues. +variable or an item. Path expressions that resolve to local or static variables +are [lvalues](expressions.html#lvalues-rvalues-and-temporaries). Using a +`static mut` variable requires an [`unsafe` block](unsafe-blocks.html) Other +paths are rvalues. + +```rust +let local_var = 3; +static STATIC_VAR: i32 = 5; +static mut STATIC_MUT_VAR: i32 = 7; +local_var; +STATIC_VAR; +unsafe { STATIC_MUT_VAR }; +``` ## Tuple expressions @@ -233,18 +294,29 @@ take a shared or mutable borrow of the reciever if needed. When resolving method calls on an expression of type `A`, Rust will use the following order: -1. Inherent methods, with receiver or type `A`, `&A`, `&mut A`. +1. Inherent methods, with receiver of type `A`, `&A`, `&mut A`. 1. Trait methods with receiver of type `A`. 1. Trait methods with receiver of type `&A`. 1. Trait methods with receiver of type `&mut A`. 1. If it's possible, Rust will then repeat steps 1-5 with `::Target`, and insert a dereference operator. +1. If `A` is now an [array](#types.html#array-and-slice-types) type, then + repeat steps 1-4 with the corresponding slice type. + +Note: that in steps 1-4 `Self` may not be the same as `A`. For example in this +example `Self` is `&A`, not `A` +```rust +impl<'a> Trait for &'a A { + fn method(self) {} +} +``` -Note: in steps 1-4 the method doesn't have to be implemented on `A`. For -example in step 3 the trait could be implemented for `&A` with the method -taking `self`. If a step is reached where there is more than one possible -method, then it is a compiler error. To resolve this use THIS ISN'T IN THE -REFERENCE!!!!!!!! +Another note: this process does not use the mutablility or lifetime of the +receiver, or whether `unsafe` methods can currently be called to resolve +methods. The constraints instead lead to compiler errors. + +If a step is reached where there is more than one possible method, then it is a +compiler error. To resolve this use THIS ISN'T IN THE REFERENCE!!!!!!!! ```rust let pi: Result = "3.14".parse(); @@ -255,11 +327,11 @@ let log_pi = pi.unwrap_or(0.0).log(2.72); ## Field expressions A _field expression_ consists of an expression followed by a single dot and an -[identifier](identifiers.html), when not immediately followed by a parenthesized expression-list -(the latter is always a [method call expression](#method-call-expressions)). A -field expression denotes a field of a [struct](types.html#struct-types). To -call a function stored in a struct parentheses are needed around the field -epression +[identifier](identifiers.html), when not immediately followed by a +parenthesized expression-list (the latter is always a [method call +expression](#method-call-expressions)). A field expression denotes a field of a +[struct](types.html#struct-types). To call a function stored in a struct +parentheses are needed around the field epression ```rust,ignore mystruct.myfield; @@ -420,46 +492,38 @@ let y = 0..10; assert_eq!(x, y); ``` -Similarly, the `...` operator will construct an object of one of the -`std::ops::RangeInclusive` variants. - -```rust -# #![feature(inclusive_range_syntax)] -1...2; // std::ops::RangeInclusive -...4; // std::ops::RangeToInclusive -``` - -The following expressions are equivalent. - -```rust -# #![feature(inclusive_range_syntax, inclusive_range)] -let x = std::ops::RangeInclusive::NonEmpty {start: 0, end: 10}; -let y = 0...10; +## Operator expressions -assert_eq!(x, y); -``` +Operators are defined for built in types by the Rust language. Many of the +following operators can be overloaded using traits in `std::ops` or `std::cmp`. +Note that the traits in `std::cmp` 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. -## Operator expressions +### Overflow -Operators are defined for built in types by the Rust language. Operators will -panic when they overflow when compiled in debug mode. Many of the following -operators can be overloaded using traits in `std::ops` or `std::cmp`. Note that -the traits in `std::cmp` 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. +Integer operators will panic when they overflow when compiled in debug mode, +i.e. when one of the following happens: +* `+`, `*` or `-` create a value greater than the maximum value, or less than + the minimum value that can be stored. Includes unary `-` on the smallest + value of any signed integer type. +* `/` or `%`, where the left-hand argument is the smallest integer of a signed +integer type and the right-hand argument is `-1`. +* `<<` 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. ### Borrow operators -The `&` and `&mut` operators are unary prefix operators. When applied to an -lvalue produce a reference (pointer) to the location that the value refers to. -The lvalue is also placed into a borrowed state for the duration of the -reference. For a shared borrow (`&`), this implies that the lvalue may not be -mutated, but it may be read or shared again. For a mutable borrow (`&mut`), the -lvalue may not be accessed in any way until the borrow expires. `&mut` may only -be applied to `lvalues` that can be mutated. If the `&` or `&mut` operators are -applied to an rvalue, a temporary value is created; the lifetime of this -temporary value is defined by [syntactic rules](#temporary-lifetimes). These -operators cannot be overloaded. +The `&` (shared borrow) and `&mut` (mutable borrow) operators are unary prefix +operators. When applied to an lvalue produce a reference (pointer) to the +location that the value refers to. The lvalue is also placed into a borrowed +state for the duration of the reference. For a shared borrow (`&`), this +implies that the lvalue may not be mutated, but it may be read or shared again. +For a mutable borrow (`&mut`), the lvalue may not be accessed in any way until +the borrow expires. `&mut` evaluates its operand in a mutable lvalue context. +If the `&` or `&mut` operators are applied to an rvalue, a temporary value is +created; the lifetime of this temporary value is defined by [syntactic +rules](#temporary-lifetimes). These operators cannot be overloaded. ```rust { @@ -476,16 +540,16 @@ let mut array = [-2, 3, 9]; ### The dereference operator -When the `*` (dereference) operator is also a unary prefix operator applied to +The `*` (dereference) operator is also a unary prefix operator. When applied to a [pointer](types.html#pointer-types) it denotes the pointed-to location. If the expression is of type `&mut T` and `*mut T`, and is either a local variable, a (nested) field of a local varaince or is a mutable lvalue, then the resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be assigned to. Dereferencing a raw pointer requires `unsafe`. -On non-pointer types `*x` is equivalent to `*std::ops::Deref::deref(&x)` or -`*std::ops::Deref::deref_mut(&mut x)` depending on whether the rquired lvalue -has to be mutable. +On non-pointer types `*x` is equivalent to `*std::ops::Deref::deref(&x)` in an +[immutable lvalue context](#mutability) and`*std::ops::Deref::deref_mut(&mut +x)` in a mutable lvalue context. ```rust let x = &7; @@ -526,9 +590,11 @@ context and are moved or copied. | Symbol | Integer | `bool` | Floating Point | Overloading Trait | |--------|-------------|-------------|----------------|--------------------| -| `-` | Negation | | Negation | `std::ops::Neg` | +| `-` | Negation* | | Negation | `std::ops::Neg` | | `!` | Bitwise NOT | Logical NOT | | `std::ops::Not` | +\* Only for signed integer types. + Here are some example of these operators ```rust @@ -538,7 +604,7 @@ assert_eq!(!x, -7); assert_eq!(true, !false); ``` -### Binary Operators Expressions +### Arithmetic and Logical Binary Operators Binary operators expressions are all written with infix notation. This table summarizes the behaivour of arithmetic and logical binary operators on @@ -560,8 +626,25 @@ context and are moved or copied. | `<<` | Left Shift | | | `std::ops::Shl` | | `>>` | Right Shift* | | | `std::ops::Shr` | -\* Arithmetic right shift on signed integers, logical right shift on unsigned integers. +\* Arithmetic right shift on signed integer types, logical right shift on +unsigned integer types. +Here are examples of these operators being used. + +```rust +assert_eq!(3 + 6, 9); +assert_eq!(5.5 - 1.25, 4.25); +assert_eq!(-5 * 14, -70); +assert_eq!(14 / 3, 4); +assert_eq!(100 % 7, 2); +assert_eq!(0b1010 & 0b1100, 0b1000); +assert_eq!(0b1010 | 0b1100, 0b1110); +assert_eq!(0b1010 ^ 0b1100, 0b110); +assert_eq!(13 << 3, 104); +assert_eq!(-10 >> 2, -3); +``` + +### Comparison Operators Comparison operators are also defined both for primitive types and many type in the standard library. Unlike arithemetic and logical operators, the traits for @@ -581,19 +664,8 @@ means that the operands don't have to be sized. | `>=` | Greater than or equal to | `std::cmp::PartialOrd::ge` | | `<=` | Less than or equal to | `std::cmp::PartialOrd::le` | -Here is an example of all of these operators being used. - +Here are examples of the comparison operators being used. ```rust -assert_eq!(3 + 6, 9); -assert_eq!(5.5 - 1.25, 4.25); -assert_eq!(-5 * 14, -70); -assert_eq!(14 / 3, 4); -assert_eq!(100 % 7, 2); -assert_eq!(0b1010 & 0b1100, 0b1000); -assert_eq!(0b1010 | 0b1100, 0b1110); -assert_eq!(0b1010 ^ 0b1100, 0b110); -assert_eq!(13 << 3, 104); -assert_eq!(-10 >> 2, -3); assert!(123 == 123); assert!(23 != -12); assert!(12.5 > 12.2); From 227ac3f5a441051f1b76216cee904ffd4b854f80 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Mar 2017 11:39:11 +0000 Subject: [PATCH 26/44] More examples for method receivers. --- src/expressions.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 8203628218f81..f6bdaff77aa86 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -303,12 +303,16 @@ following order: 1. If `A` is now an [array](#types.html#array-and-slice-types) type, then repeat steps 1-4 with the corresponding slice type. -Note: that in steps 1-4 `Self` may not be the same as `A`. For example in this -example `Self` is `&A`, not `A` +Note: that in steps 1-4 `Self` may not be the same as `A`. For example ```rust +// `Self` is `&A`, receiver is `&A`. impl<'a> Trait for &'a A { fn method(self) {} } +// If `A` is `&B`, then `Self` is `B` and the receiver is `A`. +impl B { + fn method(&self) {} +} ``` Another note: this process does not use the mutablility or lifetime of the From 3dda6f8179d00a0afc3fd4b191cc28196a6bdcf7 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Mar 2017 13:26:27 +0000 Subject: [PATCH 27/44] Add some links, fix typos --- src/expressions.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index f6bdaff77aa86..47e4ef69a896a 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -42,9 +42,9 @@ rvalue context. All other expression contexts are rvalue contexts. When an lvalue is evaluated in an _rvalue context_, it denotes the value held _in_ that memory location. If value is of a type that implements `Copy`, then -the value will be copied. In other situations then if the type of the value is -[`Sized`](the-sized-trait.html) and then it may be possible to move the value. -Only the following lvalues may be moved out of: +the value will be copied. In other situations if the type of the value is +[`Sized`](the-sized-trait.html) it may be possible to move the value. Only the +following lvalues may be moved out of: * [Variables](#variables.html) which are not currently borrowed. * [Temporary values](#temporary-lifetimes). * [Fields](#field-expressions) of an lvalue which can be moved out of and @@ -66,7 +66,7 @@ _immutable_. The following expressions can create mutable lvalues: * Mutable [variables](#variables.html), which are not currently borrowed. -* Mutable `static` items. +* [Mutable `static` items](items.html#mutable-statics). * [Temporary values](#temporary-lifetimes) * [Fields](#field-expressions), this evaluates the expression in a mutable lvalue context. @@ -300,7 +300,7 @@ following order: 1. Trait methods with receiver of type `&mut A`. 1. If it's possible, Rust will then repeat steps 1-5 with `::Target`, and insert a dereference operator. -1. If `A` is now an [array](#types.html#array-and-slice-types) type, then +1. If `A` is now an [array](types.html#array-and-slice-types) type, then repeat steps 1-4 with the corresponding slice type. Note: that in steps 1-4 `Self` may not be the same as `A`. For example @@ -317,7 +317,7 @@ impl B { Another note: this process does not use the mutablility or lifetime of the receiver, or whether `unsafe` methods can currently be called to resolve -methods. The constraints instead lead to compiler errors. +methods. These constraints instead lead to compiler errors. If a step is reached where there is more than one possible method, then it is a compiler error. To resolve this use THIS ISN'T IN THE REFERENCE!!!!!!!! From ca6fb9b0be898332b508d08edc4551e615fd47a7 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Mar 2017 13:27:44 +0000 Subject: [PATCH 28/44] Fields can be borrowed/moved separately --- src/expressions.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/expressions.md b/src/expressions.md index 47e4ef69a896a..eab5960aaa9f3 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -353,6 +353,24 @@ Also, if the type of the expression to the left of the dot is a pointer, it is automatically dereferenced as many times as necessary to make the field access possible. In cases of ambiguity, we prefer fewer autoderefs to more. +Finally the fields of a struct, a reference to a struct, or a `Box` containing +a struct are treated as spearate entities when borrowing. If the struct does +not implement [`Drop`](#the-drop-trait) this also applies to moving where +possible. This also does not apply if automatic dereferencing is done though +other types. +```rust +# struct A { f1: String, f2: String, f3: String } +# let mut x = A { +# f1: "f1".to_string(), +# f2: "f2".to_string(), +# f3: "f3".to_string() +# }; +let a: &mut String = &mut x.f1; // x.f1 borrowed mutably +let b: &String = &x.f2; // x.f2 borrowed immutably +let c: &String = &x.f2; +let d: String = x.f3; // Move out of x.f3 +``` + ## Call expressions A _call expression_ consists of an expression followed by a parenthesized From e9fc5cdf4c9cd328ff204003b3591bdd1e71c212 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Mar 2017 14:33:48 +0000 Subject: [PATCH 29/44] More small improvements --- src/expressions.md | 56 ++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index eab5960aaa9f3..9fc92bf299606 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -342,7 +342,7 @@ mystruct.myfield; foo().x; (Struct {a: 10, b: 20}).a; mystruct.method(); // Method expression -(mystruct.function_field)() // Call expression +(mystruct.function_field)() // Call expression containing a field expression ``` A field access is an [lvalue](expressions.html#lvalues-rvalues-and-temporaries) @@ -378,10 +378,10 @@ expression-list. It invokes a function, providing zero or more input variables. If the function eventually returns, then the expression completes. For [non-function types](types.html#function-types), the expression f(...) uses the method on one of the `std::ops::Fn`, `std::ops::FnMut` or `std::ops::FnOnce` -traits, which differ in whether they take the type by reference, mutable -refernece, or take ownership respectively. An automatic borrow will be taken if -needed. Rust will also automatically dereference `f` as required. Some examples -of call expressions: +traits (or the correspond traits in `core::ops`), which differ in whether they +take the type by reference, mutable refernece, or take ownership respectively. +An automatic borrow will be taken if needed. Rust will also automatically +dereference `f` as required. Some examples of call expressions: ```rust # fn add(x: i32, y: i32) -> i32 { 0 } @@ -473,9 +473,9 @@ When the array is mutable, the resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be assigned to. For other types an index expression `a[b]` is equivalent to `*std::ops::Index::index(&a, b)`, or `*std::opsIndexMut::index_mut(&mut a, b)` -when needed in a mutable context (these traits also exist in `core::ops`). Just -as with methods, Rust will also insert dereference operations on `a` repeatedly -until it finds an implementation. +in a mutable lvalue context (these traits also exist in `core::ops`). Just as +with methods, Rust will also insert dereference operations on `a` repeatedly +to find an implementation. Indices are zero-based, and are of type `usize` for arrays and slices. Vector access is bounds-checked at compile-time for constant arrays being accessed @@ -496,7 +496,8 @@ arr[10]; // panics ## Range expressions -The `..` operator will construct an object of one of the `std::ops::Range` variants. +The `..` operator will construct an object of one of the `std::ops::Range` (or +`core::ops::Range`) variants. ```rust 1..2; // std::ops::Range @@ -520,7 +521,8 @@ Operators are defined for built in types by the Rust language. Many of the following operators can be overloaded using traits in `std::ops` or `std::cmp`. Note that the traits in `std::cmp` 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. +functions that use these traits as bounds. All traits here also exist in `core` +with the same names. ### Overflow @@ -530,7 +532,7 @@ i.e. when one of the following happens: the minimum value that can be stored. Includes unary `-` on the smallest value of any signed integer type. * `/` or `%`, where the left-hand argument is the smallest integer of a signed -integer type and the right-hand argument is `-1`. + integer type and the right-hand argument is `-1`. * `<<` 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. @@ -778,22 +780,22 @@ The precedence of Rust operators is ordered as follows, going from strong to weak. Binary Operators at the same precedence level are evaluated in the order given by their associativity. -| Operator | Associativity | -|-----------------------------|-------------------------| -| `?` | | -| Unary `-` `*` `!` `&` `&mut` | | -| `as` `:` | Left to Right | -| `*` `/` `%` | Left to Right | -| `+` `-` | Left to Right | -| `<<` `>>` | Left to Right | -| `&` | Left to Right | -| `^` | Left to Right | -| | | Left to Right | -| `==` `!=` `<` `>` `<=` `>=` | Require parentheses | -| `&&` | Left to Right | -| || | Left to Right | -| `..` `...` | Require parentheses | -| `<-` | Right to Left | +| Operator | Associativity | +|-----------------------------|---------------------| +| `?` | | +| Unary `-` `*` `!` `&` `&mut` | | +| `as` `:` | Left to Right | +| `*` `/` `%` | Left to Right | +| `+` `-` | Left to Right | +| `<<` `>>` | Left to Right | +| `&` | Left to Right | +| `^` | Left to Right | +| | | Left to Right | +| `==` `!=` `<` `>` `<=` `>=` | Require parentheses | +| `&&` | Left to Right | +| || | Left to Right | +| `..` `...` | Require parentheses | +| `<-` | Right to Left | | `=` `+=` `-=` `*=` `/=` `%=` `&=` |= `^=` `<<=` `>>=` | Right to Left | From 80619cc97c3b24a3c4e2e8481e8c40466b6b8c07 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Mar 2017 16:02:10 +0000 Subject: [PATCH 30/44] Explain that traits are duplicated in core once --- src/expressions.md | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 9fc92bf299606..642a05307bb72 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -141,6 +141,12 @@ Implicit borrows may be taken in the following expressions: * Operands of [comparison operators](#comparison-operators) * Left operands of the [compound assignment](#compound-assignment-expressions) +## Traits + +Many of the following operators and expressions can also be overloaded for +other types using traits in `std::ops` or `std::cmp`, these traits here also +exist in `core::ops` and `core::cmp` with the same names. + ## Literal expressions A _literal expression_ consists of one of the [literal](tokens.html#literals) @@ -324,7 +330,7 @@ compiler error. To resolve this use THIS ISN'T IN THE REFERENCE!!!!!!!! ```rust let pi: Result = "3.14".parse(); -let log_pi = pi.unwrap_or(0.0).log(2.72); +let log_pi = pi.unwrap_or(1.0).log(2.72); # assert!(1.14 < log_pi && log_pi < 1.15) ``` @@ -378,10 +384,10 @@ expression-list. It invokes a function, providing zero or more input variables. If the function eventually returns, then the expression completes. For [non-function types](types.html#function-types), the expression f(...) uses the method on one of the `std::ops::Fn`, `std::ops::FnMut` or `std::ops::FnOnce` -traits (or the correspond traits in `core::ops`), which differ in whether they -take the type by reference, mutable refernece, or take ownership respectively. -An automatic borrow will be taken if needed. Rust will also automatically -dereference `f` as required. Some examples of call expressions: +traits, which differ in whether they take the type by reference, mutable +refernece, or take ownership respectively. An automatic borrow will be taken if +needed. Rust will also automatically dereference `f` as required. Some examples +of call expressions: ```rust # fn add(x: i32, y: i32) -> i32 { 0 } @@ -473,9 +479,8 @@ When the array is mutable, the resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be assigned to. For other types an index expression `a[b]` is equivalent to `*std::ops::Index::index(&a, b)`, or `*std::opsIndexMut::index_mut(&mut a, b)` -in a mutable lvalue context (these traits also exist in `core::ops`). Just as -with methods, Rust will also insert dereference operations on `a` repeatedly -to find an implementation. +in a mutable lvalue context. Just as with methods, Rust will also insert +dereference operations on `a` repeatedly to find an implementation. Indices are zero-based, and are of type `usize` for arrays and slices. Vector access is bounds-checked at compile-time for constant arrays being accessed @@ -518,11 +523,8 @@ assert_eq!(x, y); ## Operator expressions Operators are defined for built in types by the Rust language. Many of the -following operators can be overloaded using traits in `std::ops` or `std::cmp`. -Note that the traits in `std::cmp` 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. All traits here also exist in `core` -with the same names. +following operators can also be overloaded using traits in `std::ops` or +`std::cmp`. ### Overflow @@ -672,12 +674,14 @@ assert_eq!(-10 >> 2, -3); Comparison operators are also defined both for primitive types and many type in the standard library. Unlike arithemetic and logical operators, the traits for -overloading the operators the traits for these operators require that they are -implemented to define actual comparisons. Many functions and macros in the -standard library can then use that assumption (although not to ensure safety). -Unlike the arithmetic and logical operators above, these operators implicitly -take shared borrows of their operands, evaluating them in lvalue context. This -means that the operands don't have to be sized. +overloading the operators the traits for 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. Many +functions and macros in the standard library can then use that assumption +(although not to ensure safety). Unlike the arithmetic and logical operators +above, these operators implicitly take shared borrows of their operands, +evaluating them in lvalue context. This means that the operands don't have to +be moved out of. | Symbol | Meaning | Overloading method | |--------|--------------------------|----------------------------| From ac2428ef329af75a24739cf12be4ba0cbb23c7a0 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Mar 2017 16:38:08 +0000 Subject: [PATCH 31/44] Clarify that blocks are rvalues --- src/expressions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/expressions.md b/src/expressions.md index 642a05307bb72..3f27ff53f154f 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -288,6 +288,9 @@ let x: i32 = { println!("Hello."); 5 }; assert_eq!(5, x); ``` +Blocks are always [rvalues](#lvalues-and-rvalues) and evaluate the last +expression in rvalue context. + ## Method-call expressions A _method call_ consists of an expression followed by a single dot, an From b62a14e45f1e88e2829665ac608e8d4b61e9d170 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 24 Mar 2017 22:40:55 +0000 Subject: [PATCH 32/44] Improve comparison examples --- src/expressions.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 3f27ff53f154f..31457f10cc06f 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -128,7 +128,7 @@ operator implicitly borrows it's operands: let a: &[i32] = &[1, 2, 3]; let b: &[i32] = &vec![1, 2, 3]; *a == *b; -/// Equivalent form: +// Equivalent form: ::std::cmp::PartialEq::eq(&*a, &*b); ``` @@ -683,8 +683,14 @@ define actual comparisons by functions that use these traits as bounds. Many functions and macros in the standard library can then use that assumption (although not to ensure safety). Unlike the arithmetic and logical operators above, these operators implicitly take shared borrows of their operands, -evaluating them in lvalue context. This means that the operands don't have to -be moved out of. +evaluating them in lvalue context: +```rust +a == b; +// is equivalent to +::std::cmp::PartialEq::eq(&a, &b); +``` + +This means that the operands don't have to be moved out of. | Symbol | Meaning | Overloading method | |--------|--------------------------|----------------------------| From 911b670329063bc5f666fc3629624d59f87d2739 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 30 Mar 2017 21:34:51 +0100 Subject: [PATCH 33/44] Yet more changes * Add unsafe blocks * Use some actual paths to show off paths * Show enum variant constructors * Explain tuple indexing * Add full precedence list for future reference. --- src/expressions.md | 103 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 31457f10cc06f..89de1a3c4b0c6 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -165,16 +165,18 @@ boolean value, or the unit value. A [path](paths.html) used as an expression context denotes either a local variable or an item. Path expressions that resolve to local or static variables are [lvalues](expressions.html#lvalues-rvalues-and-temporaries). Using a -`static mut` variable requires an [`unsafe` block](unsafe-blocks.html) Other +`static mut` variable requires an [`unsafe` block](#unsafe-block) Other paths are rvalues. ```rust +mod globals { + static STATIC_VAR: i32 = 5; + static mut STATIC_MUT_VAR: i32 = 7; +} let local_var = 3; -static STATIC_VAR: i32 = 5; -static mut STATIC_MUT_VAR: i32 = 7; local_var; -STATIC_VAR; -unsafe { STATIC_MUT_VAR }; +globals::STATIC_VAR; +unsafe { globals::STATIC_MUT_VAR }; ``` ## Tuple expressions @@ -266,6 +268,22 @@ Point3d { x: x, y: y_value, z: z }; Point3d { x, y: y_value, z }; ``` +### Enumeration Variant expressions + +Enumeration variants can be constructed similarly to structs, using a path to +an enum variant instead of a struct: + +```rust +# enum Message { +# Quit, +# WriteString(String), +# Move { x: i32, y: i32 }, +# } +let q = Message::Quit; +let w = Message::WriteString("Some string".to_string()); +let m = Message::Move { x: 50, y: 200 }; +``` + ## Block expressions A _block expression_ is similar to a module in terms of the declarations that @@ -291,6 +309,13 @@ assert_eq!(5, x); Blocks are always [rvalues](#lvalues-and-rvalues) and evaluate the last expression in rvalue context. +### `unsafe` blocks + +_See [`unsafe` block](unsafe-blocks.html) for more information on when to use `unsafe`_ + +A block of code can be prefixed with the `unsafe` keyword, to permit calling +`unsafe` functions or dereferencing raw pointers within a safe function. + ## Method-call expressions A _method call_ consists of an expression followed by a single dot, an @@ -301,6 +326,12 @@ dynamically dispatching if the left-hand-side expression is an indirect [trait object](types.html#trait-objects). Method call expressions will automatically take a shared or mutable borrow of the reciever if needed. +```rust +let pi: Result = "3.14".parse(); +let log_pi = pi.unwrap_or(1.0).log(2.72); +# assert!(1.14 < log_pi && log_pi < 1.15) +``` + When resolving method calls on an expression of type `A`, Rust will use the following order: 1. Inherent methods, with receiver of type `A`, `&A`, `&mut A`. @@ -312,7 +343,8 @@ following order: 1. If `A` is now an [array](types.html#array-and-slice-types) type, then repeat steps 1-4 with the corresponding slice type. -Note: that in steps 1-4 `Self` may not be the same as `A`. For example +Note: that in steps 1-4 the receiver is used, not the type of `Self`, which may +not be the same as `A`. For example ```rust // `Self` is `&A`, receiver is `&A`. impl<'a> Trait for &'a A { @@ -328,13 +360,14 @@ Another note: this process does not use the mutablility or lifetime of the receiver, or whether `unsafe` methods can currently be called to resolve methods. These constraints instead lead to compiler errors. -If a step is reached where there is more than one possible method, then it is a -compiler error. To resolve this use THIS ISN'T IN THE REFERENCE!!!!!!!! +If a step is reached where there is more than one possible method (where +generic methods or traits are considered the same), then it is a compiler +error. To resolve this either use more distinctive names, or call the method as +a function, using the required trait name in the path: -```rust -let pi: Result = "3.14".parse(); -let log_pi = pi.unwrap_or(1.0).log(2.72); -# assert!(1.14 < log_pi && log_pi < 1.15) +```rust,ignore +Trait::method(a, b) +::method(a, b); ``` ## Field expressions @@ -367,6 +400,7 @@ a struct are treated as spearate entities when borrowing. If the struct does not implement [`Drop`](#the-drop-trait) this also applies to moving where possible. This also does not apply if automatic dereferencing is done though other types. + ```rust # struct A { f1: String, f2: String, f3: String } # let mut x = A { @@ -380,6 +414,23 @@ let c: &String = &x.f2; let d: String = x.f3; // Move out of x.f3 ``` +### Tuple indexing expressions + +[Tuples](types.html#tuple-types) and [struct tuples](items.html#structs) can be +indexed using the number corresponding to the possition of the field. The index +must be a [decimal literal](tokens.html#integer-literals) with no underscores +or suffix. Tuple indexing expressions also differ from field expressions in +that they can unabiguously be called as a function. In all other aspects they +have the same behaviour. + +```rust +# struct Point(f32, f32); +let pair = (1, 2); +assert_eq!(pair.1, 2); +let unit_x = Point(1.0, 0.0); +assert_eq!(unit_x.0, 1.0); +``` + ## Call expressions A _call expression_ consists of an expression followed by a parenthesized @@ -609,7 +660,7 @@ println!("{:?}", res); # assert!(res.is_err()) ``` -### Other prefix unary operators +### Negation operators This table summarizes the behaivour of the last two unary operators on primitive types and which traits are used to overload these operators for other @@ -795,21 +846,25 @@ given by their associativity. | Operator | Associativity | |-----------------------------|---------------------| +| paths | | +| block expressions
control flow block expressions
tuple expressions
array expressions
(braced) struct and variant expressions
method calls
field expressions | left to right | +| function calls
tuple struct expressions
index expressions | | | `?` | | | Unary `-` `*` `!` `&` `&mut` | | -| `as` `:` | Left to Right | -| `*` `/` `%` | Left to Right | -| `+` `-` | Left to Right | -| `<<` `>>` | Left to Right | -| `&` | Left to Right | -| `^` | Left to Right | -| | | Left to Right | +| `as` `:` | left to right | +| `*` `/` `%` | left to right | +| `+` `-` | left to right | +| `<<` `>>` | left to right | +| `&` | left to right | +| `^` | left to right | +| | | left to right | | `==` `!=` `<` `>` `<=` `>=` | Require parentheses | -| `&&` | Left to Right | -| || | Left to Right | +| `&&` | left to right | +| || | left to right | | `..` `...` | Require parentheses | -| `<-` | Right to Left | -| `=` `+=` `-=` `*=` `/=` `%=` `&=` |= `^=` `<<=` `>>=` | Right to Left | +| `<-` | right to left | +| `=` `+=` `-=` `*=` `/=` `%=` `&=` |= `^=` `<<=` `>>=` | right to left | +| `return` `break` `continue`
Lambda expressions | right to left | ## Grouped expressions From 7c16ff2e760bc17e8eeeaff64cb39de38d6b68cc Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 1 Apr 2017 20:55:46 +0100 Subject: [PATCH 34/44] Document constexpr and casts --- src/expressions.md | 146 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 129 insertions(+), 17 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 89de1a3c4b0c6..15365c6a7a687 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -67,7 +67,7 @@ _immutable_. The following expressions can create mutable lvalues: * Mutable [variables](#variables.html), which are not currently borrowed. * [Mutable `static` items](items.html#mutable-statics). -* [Temporary values](#temporary-lifetimes) +* [Temporary values](#temporary-lifetimes). * [Fields](#field-expressions), this evaluates the expression in a mutable lvalue context. * [Dereferenes](#the-dereference-operator) of a `*mut T` pointer. @@ -133,13 +133,13 @@ let b: &[i32] = &vec![1, 2, 3]; ``` Implicit borrows may be taken in the following expressions: -* Left operand in [method-call expressions](#method-call-expressions) -* Left operand in [field expressions](#field-expressions) -* Left operand in [call expressions](#call-expressions) -* Left operand in [index expressions](#index-expressions) -* Operand of the [dereference](#the-dereference-operator) (`*`) operator -* Operands of [comparison operators](#comparison-operators) -* Left operands of the [compound assignment](#compound-assignment-expressions) +* Left operand in [method-call expressions](#method-call-expressions). +* Left operand in [field expressions](#field-expressions). +* Left operand in [call expressions](#call-expressions). +* Left operand in [index expressions](#index-expressions). +* Operand of the [dereference](#the-dereference-operator) (`*`) operator. +* Operands of [comparison operators](#comparison-operators). +* Left operands of the [compound assignment](#compound-assignment-expressions). ## Traits @@ -147,6 +147,45 @@ Many of the following operators and expressions can also be overloaded for other types using traits in `std::ops` or `std::cmp`, these traits here also exist in `core::ops` and `core::cmp` with the same names. +## Constant expressions + +Certain types of expressions can be evaluated at compile time. These are called +_constant expressions_. The following expressions are constant expressions, so +long as any operands are also constant expressions. Certain places may put +further restrictions on which constant expressions may be used, for example, +[statics](items.html#static-items) can't be used when defining a +[constant](items.html#constant-items). + +* [Literals](#literal-expressions). +* [Paths](#paths) to [functions](items.html#functions) and constants, recursion + is not allowed however. +* Statics, so long as only their address, not their value, is used, even with. +* [Tuple expressions](#tuple-expressions). +* [Array expressions](#array-expressions). +* [Struct expressions](#struct-expressions), where the type does not implement + [`Drop`](the-drop-trait.html). +* [Variant expressions](#enumeration-variant-expressions), where the + enumeration type does not implement `Drop`. +* [Block expressions](#block-expressions) (and `unsafe` blocks) which contain + only items and possibly a (constant) tail expression. +* [Field expressions](#field-expressions). +* [Index expressions](#index-expressions), indexing a [array or + slice](types.html#array-and-slice-types) with a `usize`. +* [Range expressions](#range-expressions). +* [Lambda expressions](#lambda-expressions) which don't capture variables from + the environment. +* Built in [negation](#negation-operators), [arithmetic, + logical](#arithmetic-and-logical-binary-operators), + [comparison](#comparison-operators) or [lazy + boolean](#lazy-boolean-operators) operatators used on integer and floating + point types, `bool` and `char`. +* Shared [borrow expressions](#borrow-operators). +* The [dereference operator](#dereference-operator), but not to circumvent the + rule on statics. +* [Grouped expressions](#grouped-expressions). +* [Cast expressions](#type-cast-expressions), except pointer to address and + function pointer to address casts. + ## Literal expressions A _literal expression_ consists of one of the [literal](tokens.html#literals) @@ -177,6 +216,9 @@ let local_var = 3; local_var; globals::STATIC_VAR; unsafe { globals::STATIC_MUT_VAR }; +let some_constructor = Option::::Some; +let push_integer = Vec::::push; +let slice_eq = <[i32]>::eq; ``` ## Tuple expressions @@ -205,11 +247,13 @@ of the [path](paths.html) of a [struct item](items.html#structs), followed by a brace-enclosed list of zero or more comma-separated name-value pairs, providing the field values of a new instance of the struct. A field name can be any [identifier](identifiers.html), and is separated from its value expression by a -colon. The location denoted by a struct field is mutable if and only if the -enclosing struct is mutable. Struct expressions can't be used directly in the +colon. In the case of a tuple structs the field names are instead decimal +integer literals, containing no underscores or leading zeros, corresponding to +the position of the field. Struct expressions can't be used directly in the head of an [`if`](#if-expressions), [`while`](#while-loops), [`match`](#match-expressions), [`for`](#for-expressions), [`if -let`](#if-let-expressions) or [`while let`](#while-let-loops) expression. +let`](#if-let-expressions) or [`while let`](#while-let-loops) expression. But +struct expressions can still be in used inside parentheses, for example. A _tuple struct expression_ consists of the [path](paths.html) of a [struct item](items.html#structs), followed by a parenthesized list of one or more @@ -230,6 +274,7 @@ The following are examples of struct expressions: Point {x: 10.0, y: 20.0}; NothingInMe {}; TuplePoint(10.0, 20.0); +TuplePoint { 0: 10.0, 1: 20.0 }; // Same as above line let u = game::User {name: "Joe", age: 35, score: 100_000}; some_fn::(Cookie); ``` @@ -796,12 +841,79 @@ fn average(values: &[f64]) -> f64 { } ``` -Some of the conversions which can be done through the `as` operator can also be -done implicitly at various points in the program, such as argument passing and -assignment to a `let` binding with an explicit type. Implicit conversions are -limited to "harmless" conversions that do not lose information and which have -minimal or no risk of surprising side-effects on the dynamic execution -semantics. +`as` can be used to explicitly perform [coercions](type-coercions.html), as +well as the following additional casts. We write `*T` as short for either +`*const T` or `*mut T` + +| Type of `e` | `U` | Cast performed by `e as U` | +|-----------------------|-----------------------|----------------------------------| +| Integer or Float type | Integer or Float type | Numeric cast | +| C-like enum | Integer type | Enum cast | +| `bool` or `char` | Integer type | Primitive to integer cast | +| `u8` | `char` | `u8` to `char` cast | +| `*T`, `&T` or `&mut T`| `*V` where `V: Sized` | Pointer to pointer cast | +| `*T` where `T: Sized` | Numeric type | Pointer to address cast | +| Integer type | `*V` where `V: Sized` | Address to pointer cast | +| [Function pointer](type.html#function-types) | `*V` where `V: Sized` | Function pointer to pointer cast | +| Function pointer | Interger | Function pointer to address cast | + + +* `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* + * Casting between two integers of the same size (e.g. i32 -> u32) is a no-op + * Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will + truncate + * Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will + * zero-extend if the source is unsigned + * sign-extend if the source is signed + * Casting from a float to an integer will round the float towards zero + * **[NOTE: currently this will cause Undefined Behavior if the rounded + value cannot be represented by the target integer type][float-int]**. + This includes Inf and NaN. This is a bug and will be fixed. + * Casting from an integer to float will produce the floating point + representation of the integer, rounded if necessary (rounding strategy + unspecified) + * Casting from an f32 to an f64 is perfect and lossless + * Casting from an f64 to an f32 will produce the closest possible value + (rounding strategy unspecified) + * **[NOTE: currently this will cause Undefined Behavior if the value + is finite but larger or smaller than the largest or smallest finite + value representable by f32][float-float]**. This is a bug and will + be fixed. +* `e` is a C-like enum (with no data attached to the variants), and `U` is an + integer type; *enum-cast* + * What are the guarantees here? Equivalent to C? +* `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast* + * `false` casts to `0`, `true` casts to `1`? + * `char` casts to the value of the code point, truncating if required? +* `e` has type `u8` and `U` is `char`; *u8-char-cast* + * Interprets the `u8` as a code point? +* `e` has type `*T`, `U` has type `*U_0`, and either `U_0: Sized` or + `unsize_kind(T) == unsize_kind(U_0)`; a *ptr-ptr-cast* + * Points at same location? + * Alignment?? + * Fat pointers have the same "additional information"? + * Is unsize_kind described anywhere? + * Round trips? +* `e` has type `*T` and `U` is a numeric type, while `T: Sized`; + *ptr-addr-cast* + * What do we guarantee here? + * Equivalent to `mem::transmute` followed by truncation/extension? + * Extend as though the pointer is unsigned? +* `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast* + * Alignment?? + * Round trips with pointer address casts (either way)? + * Probably out of scope, but is 'getting (un)lucky' with addresses defined? + * Use in embedded? + * Does casting 0 in this way guaranteed to be a null pointer? +* `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast* + * Equivalent to taking reference to first element and csating (if n > 0)? +* `e` is a function pointer type and `U` has type `*T`, while `T: Sized`; + *fptr-ptr-cast* + * Same concerns as with pointer to pointer casts +* `e` is a function pointer type and `U` is an integer; *fptr-addr-cast* + * Same concerns as with pointer to address casts + +TODO: Explain every last one of these... ### Assignment expressions From e654bf520e1c15cc1cad0791dd2af0f1333c31e7 Mon Sep 17 00:00:00 2001 From: matthewjasper Date: Sun, 9 Apr 2017 16:42:15 +0100 Subject: [PATCH 35/44] Fix spelling, document rfcs 736, 968, 1229, 1535. --- src/expressions.md | 141 +++++++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 61 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 15365c6a7a687..c661fac45abe3 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -52,8 +52,8 @@ following lvalues may be moved out of: * The result of [dereferencing](#the-dereference-operator) an expression with type `Box` and that can also be moved out of. -Moving out of an lvalue deinitialises that location (if it comes from a local -vairable), so that it can't be read from again. In all other cases, trying to +Moving out of an lvalue deinitializes that location (if it comes from a local +variable), so that it can't be read from again. In all other cases, trying to use an lvalue in an rvalue context is an error. ### Mutability @@ -74,14 +74,14 @@ The following expressions can create mutable lvalues: * Dereference of a variable, or field of a variable, with type `&mut T`. Note: this is an exception to the next rule. * Dereferences of a type that implements `DerefMut`, this then requires that - the value being derefenced is evalutated is a mutable lvalue context. + the value being dereferenced is evaluated is a mutable lvalue context. * [Indexing](#index-expressions) of a type that implements `DerefMut`, this then evalutes the value being indexed (but not the index) in mutable lvalue context. ### Temporary lifetimes -When using an rvalue in most lvalue contexts, a temporary un-named lvalue is +When using an rvalue in most lvalue contexts, a temporary unnamed lvalue is created and used instead. The lifetime of temporary values is typically the innermost enclosing statement; the tail expression of a block is considered part of the statement that encloses the block. @@ -121,7 +121,7 @@ Here are some examples: Certain expressions will treat an expression as an lvalue by implicitly borrowing it. For example, it is possible to compare two unsized -[slices](#array-and-slice-types) for equality direcly, because the `==` +[slices](#array-and-slice-types) for equality directly, because the `==` operator implicitly borrows it's operands: ```rust @@ -150,16 +150,23 @@ exist in `core::ops` and `core::cmp` with the same names. ## Constant expressions Certain types of expressions can be evaluated at compile time. These are called -_constant expressions_. The following expressions are constant expressions, so -long as any operands are also constant expressions. Certain places may put -further restrictions on which constant expressions may be used, for example, -[statics](items.html#static-items) can't be used when defining a -[constant](items.html#constant-items). +_constant expressions_. Certain places, such as in +[constants](items.html#constant-items) and [statics](items.html#static-items), +require a constant expression, and are always evaluated at compile time. In +other places, such as in [`let` statements](let-statements), constant +expressions may be evaluated at compile time. If errors, such as out of bounds +[array access](#index-expressions) or [overflow](#overflow) occurs, then it is +a compiler error if the value must be evaluated at compile time, otherwise it +is just a warning, but the code will most likely panic when run. + +The following expressions are constant expressions, so long as any operands are +also constant expressions: * [Literals](#literal-expressions). -* [Paths](#paths) to [functions](items.html#functions) and constants, recursion - is not allowed however. -* Statics, so long as only their address, not their value, is used, even with. +* [Paths](#paths) to [functions](items.html#functions) and constants. Recursively + defining constants is not allowed. +* Statics, so long as only their address, not their value, is used: even + indirectly through a compilicated constant expression. \* * [Tuple expressions](#tuple-expressions). * [Array expressions](#array-expressions). * [Struct expressions](#struct-expressions), where the type does not implement @@ -177,7 +184,7 @@ further restrictions on which constant expressions may be used, for example, * Built in [negation](#negation-operators), [arithmetic, logical](#arithmetic-and-logical-binary-operators), [comparison](#comparison-operators) or [lazy - boolean](#lazy-boolean-operators) operatators used on integer and floating + boolean](#lazy-boolean-operators) operators used on integer and floating point types, `bool` and `char`. * Shared [borrow expressions](#borrow-operators). * The [dereference operator](#dereference-operator), but not to circumvent the @@ -186,6 +193,8 @@ further restrictions on which constant expressions may be used, for example, * [Cast expressions](#type-cast-expressions), except pointer to address and function pointer to address casts. +\* Only in static items. + ## Literal expressions A _literal expression_ consists of one of the [literal](tokens.html#literals) @@ -284,11 +293,12 @@ given *unit-like* struct type, this will always be the same value. A struct expression can terminate with the syntax `..` followed by an expression to denote a functional update. The expression following `..` (the -base) must have the same struct type as the new struct type being formed. -The entire expression denotes the result of constructing a new struct (with -the same type as the base expression) with the given values for the fields that +base) must have the same struct type as the new struct type being formed. The +entire expression denotes the result of constructing a new struct (with the +same type as the base expression) with the given values for the fields that were explicitly specified and the values in the base expression for all other -fields. +fields. Just as with all struct expressions, all of the fields of the struct +must be [visible](visibility-and-privacy.html). ```rust # struct Point3d { x: i32, y: i32, z: i32 } @@ -369,7 +379,7 @@ calls are resolved to 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.html#trait-objects). Method call expressions will automatically -take a shared or mutable borrow of the reciever if needed. +take a shared or mutable borrow of the receiver if needed. ```rust let pi: Result = "3.14".parse(); @@ -401,7 +411,7 @@ impl B { } ``` -Another note: this process does not use the mutablility or lifetime of the +Another note: this process does not use the mutability or lifetime of the receiver, or whether `unsafe` methods can currently be called to resolve methods. These constraints instead lead to compiler errors. @@ -422,7 +432,7 @@ A _field expression_ consists of an expression followed by a single dot and an parenthesized expression-list (the latter is always a [method call expression](#method-call-expressions)). A field expression denotes a field of a [struct](types.html#struct-types). To call a function stored in a struct -parentheses are needed around the field epression +parentheses are needed around the field expression ```rust,ignore mystruct.myfield; @@ -440,11 +450,11 @@ Also, if the type of the expression to the left of the dot is a pointer, it is automatically dereferenced as many times as necessary to make the field access possible. In cases of ambiguity, we prefer fewer autoderefs to more. -Finally the fields of a struct, a reference to a struct, or a `Box` containing -a struct are treated as spearate entities when borrowing. If the struct does -not implement [`Drop`](#the-drop-trait) this also applies to moving where -possible. This also does not apply if automatic dereferencing is done though -other types. +Finally the fields of a struct, a reference to a struct are treated as separate +entities when borrowing. If the struct does not implement +[`Drop`](#the-drop-trait) this also applies to moving out of each of its fields +where possible. This also does not apply if automatic dereferencing is done +though other types. ```rust # struct A { f1: String, f2: String, f3: String } @@ -465,8 +475,8 @@ let d: String = x.f3; // Move out of x.f3 indexed using the number corresponding to the possition of the field. The index must be a [decimal literal](tokens.html#integer-literals) with no underscores or suffix. Tuple indexing expressions also differ from field expressions in -that they can unabiguously be called as a function. In all other aspects they -have the same behaviour. +that they can unambiguously be called as a function. In all other aspects they +have the same behavior. ```rust # struct Point(f32, f32); @@ -484,7 +494,7 @@ If the function eventually returns, then the expression completes. For [non-function types](types.html#function-types), the expression f(...) uses the method on one of the `std::ops::Fn`, `std::ops::FnMut` or `std::ops::FnOnce` traits, which differ in whether they take the type by reference, mutable -refernece, or take ownership respectively. An automatic borrow will be taken if +reference, or take ownership respectively. An automatic borrow will be taken if needed. Rust will also automatically dereference `f` as required. Some examples of call expressions: @@ -500,8 +510,10 @@ A _lambda expression_ (sometimes called an "anonymous function expression") defines a closure and denotes it as a value, in a single expression. A lambda expression is a pipe-symbol-delimited (`|`) list of patterns followed by an expression. Type annotations may optionally be added for the type of the -parameters or for the return type. A lambda expession also may begin with the -`move` keyword before the initial `|`. +parameters or for the return type. If there is a return type, the expression +used for the body of the lambda must be a normal [block](#block-expressions). A +lambda expression also may begin with the `move` keyword before the initial +`|`. A lambda expression denotes a function that maps a list of parameters (`ident_list`) onto the expression that follows the `ident_list`. The patterns @@ -515,7 +527,7 @@ functions, as an abbreviation for defining and capturing a separate function. Significantly, lambda expressions _capture their environment_, which regular [function definitions](items.html#functions) do not. Without the `move` keyword, the lambda expression infers how it captures each variable from its -environment, prefering to capture by shared reference, effectively borrowing +environment, preferring to capture by shared reference, effectively borrowing all outer variables mentioned inside the closure's body. If needed the compiler will infer that instead mutable references should be taken, or that the values should be moved or copied (depending on their type) from the environment. A @@ -554,7 +566,7 @@ enclosing zero or more comma-separated expressions of uniform type in square brackets. This produces and array containing each of these values in the order they are written. -Alternatively there can be exactly two expresions inside the brackets, +Alternatively there can be exactly two expressions inside the brackets, separated by a semi-colon. The expression after the `;` must be a have type `usize` and be a constant expression that can be evaluated at compile time, such as a [literal](tokens.html#literals) or a [constant item @@ -581,15 +593,16 @@ For other types an index expression `a[b]` is equivalent to in a mutable lvalue context. Just as with methods, Rust will also insert dereference operations on `a` repeatedly to find an implementation. -Indices are zero-based, and are of type `usize` for arrays and slices. Vector -access is bounds-checked at compile-time for constant arrays being accessed -with aconstant index value. Otherwise a check will be performed at run-time -that will put the thread in a _panicked state_ if it fails. +Indices are zero-based, and are of type `usize` for arrays and slices. Array +access is a [constant expression](#constant-expressions), so bounds can be +checked at compile-time for constant arrays with a constant index value. +Otherwise a check will be performed at run-time that will put the thread in a +_panicked state_ if it fails. ```rust,should_panic -([1, 2, 3, 4])[2]; // Evluates to 3 +([1, 2, 3, 4])[2]; // Evaluates to 3 -let x = (["a", "b"])[10]; // compiler error: const index-expr is out of bounds +let x = (["a", "b"])[10]; // warning: const index-expr is out of bounds let n = 10; let y = (["a", "b"])[n]; // panics @@ -627,15 +640,17 @@ following operators can also be overloaded using traits in `std::ops` or ### Overflow -Integer operators will panic when they overflow when compiled in debug mode, -i.e. when one of the following happens: -* `+`, `*` or `-` create a value greater than the maximum value, or less than - the minimum value that can be stored. Includes unary `-` on the smallest - value of any signed integer type. -* `/` or `%`, where the left-hand argument is the smallest integer of a signed - integer type and the right-hand argument is `-1`. -* `<<` 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. +Integer operators will panic when they overflow when compiled in debug mode. +The `-C debug-assertions` and `-C overflow-checks` compiler flags can be used +to control this more directly. The following things are considered to be +overflow: +* When `+`, `*` or `-` create a value greater than the maximum value, or less + than the minimum value that can be stored. This includes unary `-` on the + smallest value of any signed integer type. +* Using `/` or `%`, where the left-hand argument is the smallest integer of a + signed integer type and the right-hand argument is `-1`. +* 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. ### Borrow operators @@ -668,7 +683,7 @@ let mut array = [-2, 3, 9]; The `*` (dereference) operator is also a unary prefix operator. When applied to a [pointer](types.html#pointer-types) it denotes the pointed-to location. If the expression is of type `&mut T` and `*mut T`, and is either a local -variable, a (nested) field of a local varaince or is a mutable lvalue, then the +variable, a (nested) field of a local variance or is a mutable lvalue, then the resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be assigned to. Dereferencing a raw pointer requires `unsafe`. @@ -687,7 +702,7 @@ assert_eq!(*y, 11); ### The `?` operator. The `?` operator can be applied to values of the `Result` type to -propogate errors. If applied to `Err(e)` it will return `Err(From::from(e))` +propagate errors. If applied to `Err(e)` it will return `Err(From::from(e))` from the enclosing function or closure. If applied to `Ok(x)` it will unwrap the value to return `x`. Unlike other unary operators `?` is written in postfix notation. `?` cannot be overloaded. @@ -707,7 +722,7 @@ println!("{:?}", res); ### Negation operators -This table summarizes the behaivour of the last two unary operators on +This table summarizes the behavior of the last two unary operators on primitive types and which traits are used to overload these operators for other types. Remember that signed integers are always represented using two's complement. The operands of all of these operators are evaluated in rvalue @@ -732,7 +747,7 @@ assert_eq!(true, !false); ### Arithmetic and Logical Binary Operators Binary operators expressions are all written with infix notation. This table -summarizes the behaivour of arithmetic and logical binary operators on +summarizes the behavior of arithmetic and logical binary operators on primitive types and which traits are used to overload these operators for other types. Remember that signed integers are always represented using two's complement. The operands of all of these operators are evaluated in rvalue @@ -772,7 +787,7 @@ assert_eq!(-10 >> 2, -3); ### Comparison Operators Comparison operators are also defined both for primitive types and many type in -the standard library. Unlike arithemetic and logical operators, the traits for +the standard library. Unlike arithmetic and logical operators, the traits for overloading the operators the traits for 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. Many @@ -851,12 +866,14 @@ well as the following additional casts. We write `*T` as short for either | C-like enum | Integer type | Enum cast | | `bool` or `char` | Integer type | Primitive to integer cast | | `u8` | `char` | `u8` to `char` cast | -| `*T`, `&T` or `&mut T`| `*V` where `V: Sized` | Pointer to pointer cast | +| `*T`, `&T` or `&mut T`| `*V` where `V: Sized` \* | Pointer to pointer cast | | `*T` where `T: Sized` | Numeric type | Pointer to address cast | | Integer type | `*V` where `V: Sized` | Address to pointer cast | +| `&[T; n]` | `*const T` | Array to pointer cast | | [Function pointer](type.html#function-types) | `*V` where `V: Sized` | Function pointer to pointer cast | -| Function pointer | Interger | Function pointer to address cast | +| Function pointer | Integer | Function pointer to address cast | +\* or `T` and `V` are compatible unsized types, e.g., both slices. * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* * Casting between two integers of the same size (e.g. i32 -> u32) is a no-op @@ -897,16 +914,18 @@ well as the following additional casts. We write `*T` as short for either * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast* * What do we guarantee here? - * Equivalent to `mem::transmute` followed by truncation/extension? + * Equivalent to `mem::transmute` to `usize`, followed by truncation/extension? * Extend as though the pointer is unsigned? + * Doing pointer arithmetic this way? * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast* * Alignment?? - * Round trips with pointer address casts (either way)? + * Round trips with pointer address casts (either way), with pointer arithmetic? * Probably out of scope, but is 'getting (un)lucky' with addresses defined? * Use in embedded? + * Equivalent to cast to `usize` followed by `mem::transmute`? * Does casting 0 in this way guaranteed to be a null pointer? * `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast* - * Equivalent to taking reference to first element and csating (if n > 0)? + * Equivalent to taking reference to first element and casting (if n > 0)? * `e` is a function pointer type and `U` has type `*T`, while `T: Sized`; *fptr-ptr-cast* * Same concerns as with pointer to pointer casts @@ -1000,7 +1019,7 @@ A `loop` expression denotes an infinite loop. A `loop` expression may optionally have a _label_. The label is written as a lifetime preceding the loop expression, as in `'foo: loop{ }`. If a label is -present, then labeled `break` and `continue` expressions nested within this +present, then labelled `break` and `continue` expressions nested within this loop may exit out of this loop or return control to its head. See [break expressions](#break-expressions) and [continue expressions](#continue-expressions). Any `loop` expression has value `()`. @@ -1074,7 +1093,7 @@ for e in v { An example of a for loop over a series of integers: ```rust -# fn bar(b:usize) { } +# fn bar(b: usize) { } for i in 0..256 { bar(i); } @@ -1098,7 +1117,7 @@ evaluates to `false`, the consequent block is skipped and any subsequent `else if` condition is evaluated. If all `if` and `else if` conditions evaluate to `false` then any `else` block is executed. An if expression evaluates to the same value as the executed block, or `()` if no block is evaluated. An `if` -expression must have the same type in all situtaions. +expression must have the same type in all situations. ```rust # let x = 3; From 8418895bb293d8a77d1d182f6409ff440b5140d9 Mon Sep 17 00:00:00 2001 From: Matthew Date: Wed, 19 Apr 2017 15:27:39 +0100 Subject: [PATCH 36/44] FIx a mistake in what casts are allowed --- src/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expressions.md b/src/expressions.md index c661fac45abe3..7891f0ebd9c03 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -866,7 +866,7 @@ well as the following additional casts. We write `*T` as short for either | C-like enum | Integer type | Enum cast | | `bool` or `char` | Integer type | Primitive to integer cast | | `u8` | `char` | `u8` to `char` cast | -| `*T`, `&T` or `&mut T`| `*V` where `V: Sized` \* | Pointer to pointer cast | +| `*T` | `*V` where `V: Sized` \* | Pointer to pointer cast | | `*T` where `T: Sized` | Numeric type | Pointer to address cast | | Integer type | `*V` where `V: Sized` | Address to pointer cast | | `&[T; n]` | `*const T` | Array to pointer cast | From e030480507d0879545f896237a86e7518cd00d39 Mon Sep 17 00:00:00 2001 From: Matthew Date: Sun, 14 May 2017 23:07:58 +0100 Subject: [PATCH 37/44] Clean up some notes --- src/expressions.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 7891f0ebd9c03..9dcb4e93d89de 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -932,7 +932,7 @@ well as the following additional casts. We write `*T` as short for either * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast* * Same concerns as with pointer to address casts -TODO: Explain every last one of these... +TODO: Explain the semantics of these. ### Assignment expressions @@ -973,7 +973,10 @@ assert_eq!(x, 14); The precedence of Rust operators is ordered as follows, going from strong to weak. Binary Operators at the same precedence level are evaluated in the order -given by their associativity. +given by their associativity.# + + | Operator | Associativity | |-----------------------------|---------------------| From 156a7f8b7a7158f3cf438891afe8ea05323446fa Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 26 May 2017 18:53:02 +0100 Subject: [PATCH 38/44] Fix links to loops secction --- src/expressions.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 8a499d7dcfe20..0913b4d05779f 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -260,19 +260,17 @@ colon. In the case of a tuple struct the field names are numbers corresponding to the position of the field. The numbers must be written in decimal, containing no underscores and with no leading zeros or integer suffix. -Struct expressions can't be used directly in the head of an -[`if`](#if-expressions), [`while`](#while-loops), -[`match`](#match-expressions), [`for`](#for-expressions), [`if -let`](#if-let-expressions) or [`while let`](#while-let-loops) expression. But -struct expressions can still be in used inside parentheses, for example. - -A _tuple struct expression_ consists of the [path](paths.html) of a [struct -item](items.html#structs), followed by a parenthesized list of one or more -comma-separated expressions (in other words, the path of a struct item followed -by a tuple expression). The struct item must be a tuple struct item. - -A _unit-like struct expression_ consists only of the [path](paths.html) of a -[struct item](items.html#structs). +Struct expressions can't be used directly in the head of a [loop](#loops) or an +[`if`](#if-expressions), [`if let`](#if-let-expressions) or +[`match`](#match-expressions) expression. But struct expressions can still be +in used inside parentheses, for example. + +A _tuple struct expression_ consists of the path of a struct item, followed by +a parenthesized list of one or more comma-separated expressions (in other +words, the path of a struct item followed by a tuple expression). The struct +item must be a tuple struct item. + +A _unit-like struct expression_ consists only of the path of a struct item. The following are examples of struct expressions: From 5ea3d30d9a8e72d0fbcb11b808a7c07e8931ba38 Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 26 May 2017 18:56:02 +0100 Subject: [PATCH 39/44] Remove most remaining lambda references --- src/expressions.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 0913b4d05779f..e79d865b0d37f 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -179,7 +179,7 @@ also constant expressions: * [Index expressions](#index-expressions), indexing a [array or slice](types.html#array-and-slice-types) with a `usize`. * [Range expressions](#range-expressions). -* [Lambda expressions](#lambda-expressions) which don't capture variables from +* [Closure expressions](#closure-expressions) which don't capture variables from the environment. * Built in [negation](#negation-operators), [arithmetic, logical](#arithmetic-and-logical-binary-operators), @@ -571,29 +571,29 @@ Refer to [RFC 132] for further details and motivations. [RFC 132]: https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md -## Lambda expressions +## Closure expressions -A _lambda expression_ (sometimes called an "anonymous function expression") -defines a closure and denotes it as a value, in a single expression. A lambda +A _closure expression_ (sometimes called an "anonymous function expression") +defines a closure and denotes it as a value, in a single expression. A closure expression is a pipe-symbol-delimited (`|`) list of patterns followed by an expression. Type annotations may optionally be added for the type of the parameters or for the return type. If there is a return type, the expression -used for the body of the lambda must be a normal [block](#block-expressions). A -lambda expression also may begin with the `move` keyword before the initial +used for the body of the closure must be a normal [block](#block-expressions). +A closure expression also may begin with the `move` keyword before the initial `|`. -A lambda expression denotes a function that maps a list of parameters +A closure expression denotes a function that maps a list of parameters (`ident_list`) onto the expression that follows the `ident_list`. The patterns in the `ident_list` are the parameters to the closure. If a parameter's types is not specified, then the compiler infers it from context. Each closure expression has a unique anonymous type. -Lambda expressions are most useful when passing functions as arguments to other +Closure expressions are most useful when passing functions as arguments to other functions, as an abbreviation for defining and capturing a separate function. -Significantly, lambda expressions _capture their environment_, which regular +Significantly, closure expressions _capture their environment_, which regular [function definitions](items.html#functions) do not. Without the `move` -keyword, the lambda expression infers how it captures each variable from its +keyword, the closure expression infers how it captures each variable from its environment, preferring to capture by shared reference, effectively borrowing all outer variables mentioned inside the closure's body. If needed the compiler will infer that instead mutable references should be taken, or that the values @@ -610,8 +610,8 @@ traits allow functions to accept closures using generics, even though the exact types can't be named. In this example, we define a function `ten_times` that takes a higher-order -function argument, and we then call it with a lambda expression as an argument, -followed by a lambda expression that moves values from its environment. +function argument, and we then call it with a closure expression as an argument, +followed by a closure expression that moves values from its environment. ```rust fn ten_times(f: F) where F: Fn(i32) { @@ -1069,7 +1069,7 @@ rather than are evaluated, so probably shouldn't be here. --> | `..` `...` | Require parentheses | | `<-` | right to left | | `=` `+=` `-=` `*=` `/=` `%=` `&=` |= `^=` `<<=` `>>=` | right to left | -| `return` `break` `continue`
Lambda expressions | right to left | +| `return` `break` `continue`
Closure expressions | right to left | ## Grouped expressions From baf6f8eb95c71b64846f31cc92d14ddefb0d4e5d Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 26 May 2017 19:33:55 +0100 Subject: [PATCH 40/44] Clean up some of the casts section --- src/expressions.md | 53 ++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 40 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index e79d865b0d37f..42b549da1ae2e 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -928,8 +928,8 @@ fn average(values: &[f64]) -> f64 { ``` `as` can be used to explicitly perform [coercions](type-coercions.html), as -well as the following additional casts. We write `*T` as short for either -`*const T` or `*mut T` +well as the following additional casts. `*T` is short for either +`*const T` or `*mut T`. | Type of `e` | `U` | Cast performed by `e as U` | |-----------------------|-----------------------|----------------------------------| @@ -946,7 +946,7 @@ well as the following additional casts. We write `*T` as short for either \* or `T` and `V` are compatible unsized types, e.g., both slices. -* `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast* +* Numeric cast * Casting between two integers of the same size (e.g. i32 -> u32) is a no-op * Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will truncate @@ -967,43 +967,16 @@ well as the following additional casts. We write `*T` as short for either is finite but larger or smaller than the largest or smallest finite value representable by f32][float-float]**. This is a bug and will be fixed. -* `e` is a C-like enum (with no data attached to the variants), and `U` is an - integer type; *enum-cast* - * What are the guarantees here? Equivalent to C? -* `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast* - * `false` casts to `0`, `true` casts to `1`? - * `char` casts to the value of the code point, truncating if required? -* `e` has type `u8` and `U` is `char`; *u8-char-cast* - * Interprets the `u8` as a code point? -* `e` has type `*T`, `U` has type `*U_0`, and either `U_0: Sized` or - `unsize_kind(T) == unsize_kind(U_0)`; a *ptr-ptr-cast* - * Points at same location? - * Alignment?? - * Fat pointers have the same "additional information"? - * Is unsize_kind described anywhere? - * Round trips? -* `e` has type `*T` and `U` is a numeric type, while `T: Sized`; - *ptr-addr-cast* - * What do we guarantee here? - * Equivalent to `mem::transmute` to `usize`, followed by truncation/extension? - * Extend as though the pointer is unsigned? - * Doing pointer arithmetic this way? -* `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast* - * Alignment?? - * Round trips with pointer address casts (either way), with pointer arithmetic? - * Probably out of scope, but is 'getting (un)lucky' with addresses defined? - * Use in embedded? - * Equivalent to cast to `usize` followed by `mem::transmute`? - * Does casting 0 in this way guaranteed to be a null pointer? -* `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast* - * Equivalent to taking reference to first element and casting (if n > 0)? -* `e` is a function pointer type and `U` has type `*T`, while `T: Sized`; - *fptr-ptr-cast* - * Same concerns as with pointer to pointer casts -* `e` is a function pointer type and `U` is an integer; *fptr-addr-cast* - * Same concerns as with pointer to address casts - -TODO: Explain the semantics of these. +* Enum cast + * Casts an enum to its discriminant, then uses a numeric cast if needed. +* Primitive to integer cast + * `false` casts to `0`, `true` casts to `1` + * `char` casts to the value of the code point, then uses a numeric cast if needed. +* `u8` to `char` cast + * Casts to the `char` with the corresponding code point. + +[float-int]: https://github.com/rust-lang/rust/issues/10184 +[float-float]: https://github.com/rust-lang/rust/issues/15536 ### Assignment expressions From 7cc613d57e7cbb669ec649329004a0c7f575dd53 Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 26 May 2017 19:40:25 +0100 Subject: [PATCH 41/44] Fix whitespace issues --- src/expressions.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/expressions.md b/src/expressions.md index 42b549da1ae2e..181d55b0111ae 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -45,6 +45,7 @@ _in_ that memory location. If value is of a type that implements `Copy`, then the value will be copied. In other situations if the type of the value is [`Sized`](the-sized-trait.html) it may be possible to move the value. Only the following lvalues may be moved out of: + * [Variables](#variables.html) which are not currently borrowed. * [Temporary values](#temporary-lifetimes). * [Fields](#field-expressions) of an lvalue which can be moved out of and @@ -65,6 +66,7 @@ contexts _mutable_ lvalue contexts, other lvalue contexts are called _immutable_. The following expressions can create mutable lvalues: + * Mutable [variables](#variables.html), which are not currently borrowed. * [Mutable `static` items](items.html#mutable-statics). * [Temporary values](#temporary-lifetimes). @@ -133,6 +135,7 @@ let b: &[i32] = &vec![1, 2, 3]; ``` Implicit borrows may be taken in the following expressions: + * Left operand in [method-call expressions](#method-call-expressions). * Left operand in [field expressions](#field-expressions). * Left operand in [call expressions](#call-expressions). @@ -400,6 +403,7 @@ following order: Note: that in steps 1-4 the receiver is used, not the type of `Self`, which may not be the same as `A`. For example + ```rust // `Self` is `&A`, receiver is `&A`. impl<'a> Trait for &'a A { @@ -866,6 +870,7 @@ functions and macros in the standard library can then use that assumption (although not to ensure safety). Unlike the arithmetic and logical operators above, these operators implicitly take shared borrows of their operands, evaluating them in lvalue context: + ```rust a == b; // is equivalent to @@ -884,6 +889,7 @@ This means that the operands don't have to be moved out of. | `<=` | Less than or equal to | `std::cmp::PartialOrd::le` | Here are examples of the comparison operators being used. + ```rust assert!(123 == 123); assert!(23 != -12); @@ -1092,7 +1098,7 @@ the loop conditional expression evaluates to `true`, the loop body block executes, then control returns to the loop conditional expression. If the loop conditional expression evaluates to `false`, the `while` expression completes. - An example: +An example: ```rust let mut i = 0; From 02ee9a66268bb659f167804bb0e568234be6ad9c Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 26 May 2017 19:51:57 +0100 Subject: [PATCH 42/44] Fix some things in the operator section --- src/expressions.md | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index 181d55b0111ae..f96a6e578c32c 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -772,11 +772,11 @@ assert_eq!(*y, 11); ### The `?` operator. -The `?` operator can be applied to values of the `Result` type to -propagate errors. If applied to `Err(e)` it will return `Err(From::from(e))` -from the enclosing function or closure. If applied to `Ok(x)` it will unwrap -the value to return `x`. Unlike other unary operators `?` is written in postfix -notation. `?` cannot be overloaded. +The `?` ("question mark") operator can be applied to values of the `Result` type to propagate errors. If applied to `Err(e)` it will return +`Err(From::from(e))` from the enclosing function or closure. If applied to +`Ok(x)` it will unwrap the value to return `x`. Unlike other unary operators +`?` is written in postfix notation. `?` cannot be overloaded. ```rust # use std::num::ParseIntError; @@ -871,7 +871,7 @@ functions and macros in the standard library can then use that assumption above, these operators implicitly take shared borrows of their operands, evaluating them in lvalue context: -```rust +```rust,ignore a == b; // is equivalent to ::std::cmp::PartialEq::eq(&a, &b); @@ -1018,21 +1018,15 @@ x += 4; assert_eq!(x, 14); ``` - ### Operator precedence The precedence of Rust operators is ordered as follows, going from strong to weak. Binary Operators at the same precedence level are evaluated in the order -given by their associativity.# +given by their associativity. - | Operator | Associativity | |-----------------------------|---------------------| -| paths | | -| block expressions
control flow block expressions
tuple expressions
array expressions
(braced) struct and variant expressions
method calls
field expressions | left to right | -| function calls
tuple struct expressions
index expressions | | | `?` | | | Unary `-` `*` `!` `&` `&mut` | | | `as` `:` | left to right | @@ -1048,8 +1042,6 @@ rather than are evaluated, so probably shouldn't be here. --> | `..` `...` | Require parentheses | | `<-` | right to left | | `=` `+=` `-=` `*=` `/=` `%=` `&=` |= `^=` `<<=` `>>=` | right to left | -| `return` `break` `continue`
Closure expressions | right to left | - ## Grouped expressions From b75f52a5fa46a60f67ab28a9f9c5c8d1e14e3548 Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 26 May 2017 20:24:09 +0100 Subject: [PATCH 43/44] Fix tests --- src/expressions.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index f96a6e578c32c..d9c7da28b3d3a 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -221,16 +221,16 @@ paths are rvalues. ```rust mod globals { - static STATIC_VAR: i32 = 5; - static mut STATIC_MUT_VAR: i32 = 7; + pub static STATIC_VAR: i32 = 5; + pub static mut STATIC_MUT_VAR: i32 = 7; } let local_var = 3; local_var; globals::STATIC_VAR; unsafe { globals::STATIC_MUT_VAR }; -let some_constructor = Option::::Some; +let some_constructor = Option::Some::; let push_integer = Vec::::push; -let slice_eq = <[i32]>::eq; +let slice_reverse = <[i32]>::reverse; ``` ## Tuple expressions @@ -404,7 +404,7 @@ following order: Note: that in steps 1-4 the receiver is used, not the type of `Self`, which may not be the same as `A`. For example -```rust +```rust,ignore // `Self` is `&A`, receiver is `&A`. impl<'a> Trait for &'a A { fn method(self) {} From 4f39ffba07d5d48a71bc805430c91e95417ea735 Mon Sep 17 00:00:00 2001 From: Matthew Date: Fri, 26 May 2017 23:04:12 +0100 Subject: [PATCH 44/44] Make some small improvements to phrasing and examples --- src/expressions.md | 164 +++++++++++++++++++++++++-------------------- 1 file changed, 90 insertions(+), 74 deletions(-) diff --git a/src/expressions.md b/src/expressions.md index d9c7da28b3d3a..24e2be99b3a59 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -42,11 +42,11 @@ rvalue context. All other expression contexts are rvalue contexts. When an lvalue is evaluated in an _rvalue context_, it denotes the value held _in_ that memory location. If value is of a type that implements `Copy`, then -the value will be copied. In other situations if the type of the value is -[`Sized`](the-sized-trait.html) it may be possible to move the value. Only the -following lvalues may be moved out of: +the value will be copied. In the remaining situations if the type of the value +is [`Sized`](the-sized-trait.html) it may be possible to move the value. Only +the following lvalues may be moved out of: -* [Variables](#variables.html) which are not currently borrowed. +* [Variables](variables.html) which are not currently borrowed. * [Temporary values](#temporary-lifetimes). * [Fields](#field-expressions) of an lvalue which can be moved out of and doesn't implement [`Drop`](#the-drop-trait). @@ -67,14 +67,14 @@ _immutable_. The following expressions can create mutable lvalues: -* Mutable [variables](#variables.html), which are not currently borrowed. +* Mutable [variables](variables.html), which are not currently borrowed. * [Mutable `static` items](items.html#mutable-statics). * [Temporary values](#temporary-lifetimes). -* [Fields](#field-expressions), this evaluates the expression in a mutable +* [Fields](#field-expressions), this evaluates the subexpression in a mutable lvalue context. * [Dereferenes](#the-dereference-operator) of a `*mut T` pointer. * Dereference of a variable, or field of a variable, with type `&mut T`. Note: - this is an exception to the next rule. + this is an exception to the requirement for the next rule. * Dereferences of a type that implements `DerefMut`, this then requires that the value being dereferenced is evaluated is a mutable lvalue context. * [Indexing](#index-expressions) of a type that implements `DerefMut`, this @@ -127,8 +127,13 @@ borrowing it. For example, it is possible to compare two unsized operator implicitly borrows it's operands: ```rust -let a: &[i32] = &[1, 2, 3]; -let b: &[i32] = &vec![1, 2, 3]; +# let c = [1, 2, 3]; +# let d = vec![1, 2, 3]; +let a: &[i32]; +let b: &[i32]; +# a = &c; +# b = &d; +// ... *a == *b; // Equivalent form: ::std::cmp::PartialEq::eq(&*a, &*b); @@ -144,12 +149,6 @@ Implicit borrows may be taken in the following expressions: * Operands of [comparison operators](#comparison-operators). * Left operands of the [compound assignment](#compound-assignment-expressions). -## Traits - -Many of the following operators and expressions can also be overloaded for -other types using traits in `std::ops` or `std::cmp`, these traits here also -exist in `core::ops` and `core::cmp` with the same names. - ## Constant expressions Certain types of expressions can be evaluated at compile time. These are called @@ -166,10 +165,11 @@ The following expressions are constant expressions, so long as any operands are also constant expressions: * [Literals](#literal-expressions). -* [Paths](#paths) to [functions](items.html#functions) and constants. Recursively - defining constants is not allowed. -* Statics, so long as only their address, not their value, is used: even - indirectly through a compilicated constant expression. \* +* [Paths](#paths) to [functions](items.html#functions) and constants. + Recursively defining constants is not allowed. +* Paths to statics, so long as only their address, not their value, is used. + This includes using their value indirectly through a compilicated expression. + \* * [Tuple expressions](#tuple-expressions). * [Array expressions](#array-expressions). * [Struct expressions](#struct-expressions), where the type does not implement @@ -182,8 +182,8 @@ also constant expressions: * [Index expressions](#index-expressions), indexing a [array or slice](types.html#array-and-slice-types) with a `usize`. * [Range expressions](#range-expressions). -* [Closure expressions](#closure-expressions) which don't capture variables from - the environment. +* [Closure expressions](#closure-expressions) which don't capture variables + from the environment. * Built in [negation](#negation-operators), [arithmetic, logical](#arithmetic-and-logical-binary-operators), [comparison](#comparison-operators) or [lazy @@ -198,6 +198,12 @@ also constant expressions: \* Only in static items. +## Overloading Traits + +Many of the following operators and expressions can also be overloaded for +other types using traits in `std::ops` or `std::cmp`, these traits here also +exist in `core::ops` and `core::cmp` with the same names. + ## Literal expressions A _literal expression_ consists of one of the [literal](tokens.html#literals) @@ -215,20 +221,20 @@ boolean value, or the unit value. A [path](paths.html) used as an expression context denotes either a local variable or an item. Path expressions that resolve to local or static variables -are [lvalues](expressions.html#lvalues-rvalues-and-temporaries). Using a -`static mut` variable requires an [`unsafe` block](#unsafe-block) Other -paths are rvalues. +are [lvalues](expressions.html#lvalues-rvalues-and-temporaries), other paths +are rvalues. Using a `static mut` variable requires an [`unsafe` +block](#unsafe-block). ```rust -mod globals { - pub static STATIC_VAR: i32 = 5; - pub static mut STATIC_MUT_VAR: i32 = 7; -} -let local_var = 3; +# mod globals { +# pub static STATIC_VAR: i32 = 5; +# pub static mut STATIC_MUT_VAR: i32 = 7; +# } +# let local_var = 3; local_var; globals::STATIC_VAR; unsafe { globals::STATIC_MUT_VAR }; -let some_constructor = Option::Some::; +let some_constructor = Some::; let push_integer = Vec::::push; let slice_reverse = <[i32]>::reverse; ``` @@ -301,7 +307,8 @@ entire expression denotes the result of constructing a new struct (with the same type as the base expression) with the given values for the fields that were explicitly specified and the values in the base expression for all other fields. Just as with all struct expressions, all of the fields of the struct -must be [visible](visibility-and-privacy.html). +must be [visible](visibility-and-privacy.html), even those not explicitly +named. ```rust # struct Point3d { x: i32, y: i32, z: i32 } @@ -329,7 +336,7 @@ Point3d { x, y: y_value, z }; ### Enumeration Variant expressions Enumeration variants can be constructed similarly to structs, using a path to -an enum variant instead of a struct: +an enum variant instead of to a struct: ```rust # enum Message { @@ -345,12 +352,14 @@ let m = Message::Move { x: 50, y: 200 }; ## Block expressions A _block expression_ is similar to a module in terms of the declarations that -are possible. Each block conceptually introduces a new namespace scope. Use +are possible, but can also contain [statements](statements.html) and end with +an expression. Each block conceptually introduces a new namespace scope. Use items can bring new names into scopes and declared items are in scope for only the block itself. A block will execute each statement sequentially, and then execute the -expression (if given). If the block ends in a statement, its value is `()`: +expression (if given). If the block doesn't end in an expression, its value is +`()`: ```rust let x: () = { println!("Hello."); }; @@ -365,7 +374,8 @@ assert_eq!(5, x); ``` Blocks are always [rvalues](#lvalues-and-rvalues) and evaluate the last -expression in rvalue context. +expression in rvalue context. This can be used to force moving a value +if really needed. ### `unsafe` blocks @@ -392,6 +402,7 @@ let log_pi = pi.unwrap_or(1.0).log(2.72); When resolving method calls on an expression of type `A`, Rust will use the following order: + 1. Inherent methods, with receiver of type `A`, `&A`, `&mut A`. 1. Trait methods with receiver of type `A`. 1. Trait methods with receiver of type `&A`. @@ -401,8 +412,8 @@ following order: 1. If `A` is now an [array](types.html#array-and-slice-types) type, then repeat steps 1-4 with the corresponding slice type. -Note: that in steps 1-4 the receiver is used, not the type of `Self`, which may -not be the same as `A`. For example +Note: that in steps 1-4 the receiver is used, not the type of `Self` nor the +type of `A`. For example ```rust,ignore // `Self` is `&A`, receiver is `&A`. @@ -442,8 +453,8 @@ mystruct.method(); // Method expression ``` A field access is an [lvalue](expressions.html#lvalues-rvalues-and-temporaries) -referring to the value of that field. When the type providing the field -inherits mutability, it can be [assigned](#assignment-expressions) to. +referring to the value of that field. When the subexpression is +[mutable](#mutability), the field expression is also mutable. Also, if the type of the expression to the left of the dot is a pointer, it is automatically dereferenced as many times as necessary to make the field access @@ -453,7 +464,7 @@ Finally the fields of a struct, a reference to a struct are treated as separate entities when borrowing. If the struct does not implement [`Drop`](#the-drop-trait) this also applies to moving out of each of its fields where possible. This also does not apply if automatic dereferencing is done -though other types. +though user defined types. ```rust # struct A { f1: String, f2: String, f3: String } @@ -464,7 +475,7 @@ though other types. # }; let a: &mut String = &mut x.f1; // x.f1 borrowed mutably let b: &String = &x.f2; // x.f2 borrowed immutably -let c: &String = &x.f2; +let c: &String = &x.f2; // Can borrow again let d: String = x.f3; // Move out of x.f3 ``` @@ -472,10 +483,10 @@ let d: String = x.f3; // Move out of x.f3 [Tuples](types.html#tuple-types) and [struct tuples](items.html#structs) can be indexed using the number corresponding to the possition of the field. The index -must be a [decimal literal](tokens.html#integer-literals) with no underscores -or suffix. Tuple indexing expressions also differ from field expressions in -that they can unambiguously be called as a function. In all other aspects they -have the same behavior. +must be written as a [decimal literal](tokens.html#integer-literals) with no +underscores or suffix. Tuple indexing expressions also differ from field +expressions in that they can unambiguously be called as a function. In all +other aspects they have the same behavior. ```rust # struct Point(f32, f32); @@ -577,14 +588,13 @@ Refer to [RFC 132] for further details and motivations. ## Closure expressions -A _closure expression_ (sometimes called an "anonymous function expression") -defines a closure and denotes it as a value, in a single expression. A closure -expression is a pipe-symbol-delimited (`|`) list of patterns followed by an -expression. Type annotations may optionally be added for the type of the -parameters or for the return type. If there is a return type, the expression -used for the body of the closure must be a normal [block](#block-expressions). -A closure expression also may begin with the `move` keyword before the initial -`|`. +A _closure expression_ defines a closure and denotes it as a value, in a single +expression. A closure expression is a pipe-symbol-delimited (`|`) list of +patterns followed by an expression. Type annotations may optionally be added +for the type of the parameters or for the return type. If there is a return +type, the expression used for the body of the closure must be a normal +[block](#block-expressions). A closure expression also may begin with the +`move` keyword before the initial `|`. A closure expression denotes a function that maps a list of parameters (`ident_list`) onto the expression that follows the `ident_list`. The patterns @@ -608,10 +618,10 @@ closure's type is `'static`. The compiler will determine which of the [closure traits](types.html#closure-types) the closure's type will implement by how it -acts on them. The closure will also implement [`Send`](the-send-trait.html) -and/or [`Sync`](the-sync-trait.html) if all of its captured types do. These -traits allow functions to accept closures using generics, even though the exact -types can't be named. +acts on its captured variables. The closure will also implement +[`Send`](the-send-trait.html) and/or [`Sync`](the-sync-trait.html) if all of +its captured types do. These traits allow functions to accept closures using +generics, even though the exact types can't be named. In this example, we define a function `ten_times` that takes a higher-order function argument, and we then call it with a closure expression as an argument, @@ -625,6 +635,8 @@ fn ten_times(f: F) where F: Fn(i32) { } ten_times(|j| println!("hello, {}", j)); +// With type annotations +ten_times(|j: i32| -> () { println!("hello, {}", j) }); let word = "konnichiwa".to_owned(); ten_times(move |j| println!("{}, {}", word, j)); @@ -632,17 +644,17 @@ ten_times(move |j| println!("{}, {}", word, j)); ## Array expressions -An [array](types.html#array-and-slice-types) _expression_ can be written by +An _[array](types.html#array-and-slice-types) expression_ can be written by enclosing zero or more comma-separated expressions of uniform type in square brackets. This produces and array containing each of these values in the order they are written. Alternatively there can be exactly two expressions inside the brackets, separated by a semi-colon. The expression after the `;` must be a have type -`usize` and be a constant expression that can be evaluated at compile time, -such as a [literal](tokens.html#literals) or a [constant item -item](items.html#constant-items). `[a; b]` creates an array containing `b` copies -of the value of `a`. If the expression after the semi-colon has a value +`usize` and be a [constant expression](#constant-expressions), such as a +[literal](tokens.html#literals) or a [constant +item](items.html#constant-items). `[a; b]` creates an array containing `b` +copies of the value of `a`. If the expression after the semi-colon has a value greater than 1 then this requires that the type of `a` is [`Copy`](the-copy-trait.html). @@ -715,6 +727,7 @@ Integer operators will panic when they overflow when compiled in debug mode. The `-C debug-assertions` and `-C overflow-checks` compiler flags can be used to control this more directly. The following things are considered to be overflow: + * When `+`, `*` or `-` create a value greater than the maximum value, or less than the minimum value that can be stored. This includes unary `-` on the smallest value of any signed integer type. @@ -759,7 +772,7 @@ resulting [lvalue](expressions.html#lvalues-rvalues-and-temporaries) can be assigned to. Dereferencing a raw pointer requires `unsafe`. On non-pointer types `*x` is equivalent to `*std::ops::Deref::deref(&x)` in an -[immutable lvalue context](#mutability) and`*std::ops::Deref::deref_mut(&mut +[immutable lvalue context](#mutability) and `*std::ops::Deref::deref_mut(&mut x)` in a mutable lvalue context. ```rust @@ -793,11 +806,11 @@ println!("{:?}", res); ### Negation operators -This table summarizes the behavior of the last two unary operators on -primitive types and which traits are used to overload these operators for other -types. Remember that signed integers are always represented using two's -complement. The operands of all of these operators are evaluated in rvalue -context and are moved or copied. +These are the last two unary operators. This table summarizes the behavior of +them on primitive types and which traits are used to overload these operators +for other types. Remember that signed integers are always represented using +two's complement. The operands of all of these operators are evaluated in +rvalue context so are moved or copied. | Symbol | Integer | `bool` | Floating Point | Overloading Trait | |--------|-------------|-------------|----------------|--------------------| @@ -822,7 +835,7 @@ summarizes the behavior of arithmetic and logical binary operators on primitive types and which traits are used to overload these operators for other types. Remember that signed integers are always represented using two's complement. The operands of all of these operators are evaluated in rvalue -context and are moved or copied. +context so are moved or copied. | Symbol | Integer | `bool` | Floating Point | Overloading Trait | |--------|-------------------------|-------------|----------------|--------------------| @@ -934,8 +947,8 @@ fn average(values: &[f64]) -> f64 { ``` `as` can be used to explicitly perform [coercions](type-coercions.html), as -well as the following additional casts. `*T` is short for either -`*const T` or `*mut T`. +well as the following additional casts. Here `*T` means either `*const T` or +`*mut T`. | Type of `e` | `U` | Cast performed by `e as U` | |-----------------------|-----------------------|----------------------------------| @@ -950,7 +963,10 @@ well as the following additional casts. `*T` is short for either | [Function pointer](type.html#function-types) | `*V` where `V: Sized` | Function pointer to pointer cast | | Function pointer | Integer | Function pointer to address cast | -\* or `T` and `V` are compatible unsized types, e.g., both slices. +\* or `T` and `V` are compatible unsized types, e.g., both slices, both the +same trait object. + +#### Semantics * Numeric cast * Casting between two integers of the same size (e.g. i32 -> u32) is a no-op @@ -1041,7 +1057,7 @@ given by their associativity. | || | left to right | | `..` `...` | Require parentheses | | `<-` | right to left | -| `=` `+=` `-=` `*=` `/=` `%=` `&=` |= `^=` `<<=` `>>=` | right to left | +| `=` `+=` `-=` `*=` `/=` `%=`
`&=` |= `^=` `<<=` `>>=` | right to left | ## Grouped expressions @@ -1402,7 +1418,7 @@ condition expression it expects the keyword `let` followed by a refutable pattern, an `=` and an expression. If the value of the expression on the right hand side of the `=` matches the pattern, the loop body block executes then control returns to the pattern matching statement. Otherwise, the while -expression completes. Like `while` loops, `while let` loops evaluate to `()`. +expression completes. ```rust let mut x = vec![1, 2, 3];