//@ to use a vector "digits" of the number. This is like "1337" being a vector of four digits (1, 3, 3, 7),
//@ except that we will use `u64` as type of our digits, meaning we have 2^64 individual digits. Now we just
//@ have to decide the order in which we store numbers. I decided that we will store the least significant
//@ to use a vector "digits" of the number. This is like "1337" being a vector of four digits (1, 3, 3, 7),
//@ except that we will use `u64` as type of our digits, meaning we have 2^64 individual digits. Now we just
//@ have to decide the order in which we store numbers. I decided that we will store the least significant
-//@ digit first. This means that "1337" would actually become (7, 3, 3, 1).<br/>
+//@ digit first. This means that "1337" would actually become (7, 3, 3, 1). <br/>
//@ Finally, we declare that there must not be any trailing zeros (corresponding to
//@ useless leading zeros in our usual way of writing numbers). This is to ensure that
//@ the same number can only be stored in one way.
//@ Finally, we declare that there must not be any trailing zeros (corresponding to
//@ useless leading zeros in our usual way of writing numbers). This is to ensure that
//@ the same number can only be stored in one way.
//@ `data` public - otherwise, the next parts of this course could not work on `BigInt`s. Of course, in a
//@ real program, one would make the field private to ensure that the invariant (no trailing zeros) is maintained.
pub struct BigInt {
//@ `data` public - otherwise, the next parts of this course could not work on `BigInt`s. Of course, in a
//@ real program, one would make the field private to ensure that the invariant (no trailing zeros) is maintained.
pub struct BigInt {
- // declaration for `v` here is just like the one in `let mut ...`, it says that we will locally
- // change the vector `v`.
+ // declaration for `v` here is just like the one in `let mut ...`: We completely own `v`, but Rust
+ // still asks us to make our intention of modifying it explicit. This `mut` is *not* part of the
+ // type of `from_vec` - the caller has to give up ownership of `v` anyway, so they don't care anymore
+ // what you do to it.
-//@ If you have a close look at the type of `BigInt::from_vec`, you will notice that it
-//@ consumes the vector `v`. The caller hence loses access to its vector. There is however something
+//@ If you take a close look at the type of `BigInt::from_vec`, you will notice that it
+//@ consumes the vector `v`. The caller hence loses access to its vector. However, there is something
//@ we can do if we don't want that to happen: We can explicitly `clone` the vector,
//@ which means that a full (or *deep*) copy will be performed. Technically,
//@ we can do if we don't want that to happen: We can explicitly `clone` the vector,
//@ which means that a full (or *deep*) copy will be performed. Technically,
//@ like `test_invariant` above): It is not necessary to explicitly borrow the receiver of the
//@ method. Hence you could replace `(&v).clone()` by `v.clone()` above. Just try it!
//@ like `test_invariant` above): It is not necessary to explicitly borrow the receiver of the
//@ method. Hence you could replace `(&v).clone()` by `v.clone()` above. Just try it!
match *self { /*@*/
Nothing => Nothing, /*@*/
//@ In the second arm of the match, we need to talk about the value `v`
match *self { /*@*/
Nothing => Nothing, /*@*/
//@ In the second arm of the match, we need to talk about the value `v`
//@ `Something(v)`, that would indicate that we *own* `v` in the code
//@ after the arrow. That can't work though, we have to leave `v` owned by
//@ whoever called us - after all, we don't even own `self`, we just borrowed it.
//@ `Something(v)`, that would indicate that we *own* `v` in the code
//@ after the arrow. That can't work though, we have to leave `v` owned by
//@ whoever called us - after all, we don't even own `self`, we just borrowed it.
//@ `#[derive(Clone)]` right before the definition of `SomethingOrNothing`.
// **Exercise 05.2**: Write some more functions on `BigInt`. What about a function that returns the number of
//@ `#[derive(Clone)]` right before the definition of `SomethingOrNothing`.
// **Exercise 05.2**: Write some more functions on `BigInt`. What about a function that returns the number of
//@ have to rule out mutation in the presence of aliasing. First, we define an `enum` that can hold either
//@ a number, or a string.
enum Variant {
Number(i32),
Text(String),
}
//@ have to rule out mutation in the presence of aliasing. First, we define an `enum` that can hold either
//@ a number, or a string.
enum Variant {
Number(i32),
Text(String),
}
-//@ Now consider the following piece of code. Like above, `n` will be a borrow of a part of `var`,
-//@ and since we wrote `ref mut`, the borrow will be mutable. In other words, right after the match, `ptr`
+//@ Now consider the following piece of code. Like above, `n` will be a reference to a part of `var`,
+//@ and since we wrote `ref mut`, the reference will be unique and mutable. In other words, right after the match, `ptr`
//@ points to the number that's stored in `var`, where `var` is a `Number`. Remember that `_` means
//@ "we don't care".
fn work_on_variant(mut var: Variant, text: String) {
//@ points to the number that's stored in `var`, where `var` is a `Number`. Remember that `_` means
//@ "we don't care".
fn work_on_variant(mut var: Variant, text: String) {
Variant::Number(ref mut n) => ptr = n,
Variant::Text(_) => return,
}
Variant::Number(ref mut n) => ptr = n,
Variant::Text(_) => return,
}
*ptr = 1337;
}
//@ Now, imagine what would happen if we were permitted to also mutate `var`. We could, for example,
*ptr = 1337;
}
//@ Now, imagine what would happen if we were permitted to also mutate `var`. We could, for example,
//@ I hope this example clarifies why Rust has to rule out mutation in the presence of aliasing *in general*,
//@ not just for the specific case of a buffer being reallocated, and old pointers becoming hence invalid.
//@ I hope this example clarifies why Rust has to rule out mutation in the presence of aliasing *in general*,
//@ not just for the specific case of a buffer being reallocated, and old pointers becoming hence invalid.