fn main() {
let x = 5;
println!("{}", x);
let x = 3.14;
println!("{}", x);
let x = "Hello";
println!("{}", x);
}
What happens to the previous values? My understanding is that they are not destroyed.
Is there a way to still access these values?
If they are still consuming memory space, is it possible to release that space?
What happens to the previous values?
Nothing.
Is there a way to still access these values?
No.
If they are still consuming memory space, is it possible to release that space?
No.
Now, all of the above should be true from the perspective of the code. They're not necessarily true from the perspective of the optimiser. For example, the optimiser might notice that uses of the first and second x's don't overlap, so it can re-use the stack storage of the first x for the second x.
Or it might not. The language itself, insofar as I am aware, has no opinion on the subject.
The only way I'm aware of that you can guarantee that a local variable will definitely release it's stack storage is to return from the function it's defined in.
... well, until you consider inlining, which could also make that not true.
Short version: don't worry about it, unless you're using so much stack space that it's causing actual, measurable problems.
The value can be moved out before the variable is shadowed, but
ultimately the value can't be accessed from a shadowed variable.
Answer to Q1: The decision is up to the compiler and data type and size and OS and system memory load (usually stack based data types stay to the end of the main, and heap based data types with big memory footprint may need to drop if needed).
Answer to Q2: After shadowing: No, before shadowing: Yes (Values), run this code.
Answer to Q3: After shadowing: No, before shadowing: see: Disposes of a value. and Rust manual memory management
Variable scoping and shadowing:
Advantages:
1. Since data cannot be accessed from outer scope, Data Integrity is preserved.
2. When "we need more alphabets", this is nice way to limit variables scope.
Also this works well when you need more local variables or scope.
A way to still access these values before shadowing (note: move forced the closure to take ownership of 'x'):
use std::{thread, time};
fn main() {
let mut v = vec![];
let d = time::Duration::from_millis(100);
let x = 5;
println!("{}", x);
v.push(thread::spawn(move || {
for _ in 1..10 {
thread::sleep(d);
println!("Thread 1: {}", x);
}
}));
let x = 3.14;
println!("{}", x);
v.push(thread::spawn(move || {
for _ in 1..10 {
thread::sleep(d);
println!("Thread 2: {}", x);
}
}));
let x = "Hello";
println!("{}", x);
v.push(thread::spawn(move || {
for _ in 1..10 {
thread::sleep(d);
println!("Thread 3: {}", x);
}
}));
for child in v {
let _ = child.join();
}
}
output:
5
3.14
Hello
Thread 1: 5
Thread 3: Hello
Thread 2: 3.14
Thread 2: 3.14
Thread 3: Hello
Thread 1: 5
Thread 1: 5
Thread 3: Hello
Thread 2: 3.14
Thread 2: 3.14
Thread 3: Hello
Thread 1: 5
Thread 2: 3.14
Thread 3: Hello
Thread 1: 5
Thread 2: 3.14
Thread 1: 5
Thread 3: Hello
Thread 2: 3.14
Thread 1: 5
Thread 3: Hello
Thread 3: Hello
Thread 2: 3.14
Thread 1: 5
Thread 1: 5
Thread 2: 3.14
Thread 3: Hello
Note: move forces the closure to take ownership of 'x', so the address of local x is not the same as thread x but the value is:
use std::thread;
fn main() {
let mut v = vec![];
let x = 5;
println!("{:p}", &x);
v.push(thread::spawn(move || {
println!("Thread 1: {:p}", &x);
}));
let x = 3.14;
println!("{:p}", &x);
v.push(thread::spawn(move || {
println!("Thread 2: {:p}", &x);
}));
let x = "Hello";
println!("{:p}", &x);
v.push(thread::spawn(move || {
println!("Thread 3: {:p}", &x);
}));
for child in v {
let _ = child.join();
}
}
output:
0x8bf934
0x8bf9b8
0x8bfa40
Thread 1: 0x4a3faec
Thread 2: 0x4c3fae8
Thread 3: 0x4e3fa70
As far as I know there is only one thing to keep in mind with shadowing: when values are heap allocated.
From the book:
Note that shadowing a name does not alter or destroy the value it was bound to, and the value will continue to exist until it goes out of scope, even if it is no longer accessible by any means
the previous value is not more accessible after shadowing and it will be
destroyed at the end of the scope, not when the variable is shadowed.
If value are on the stack there is nothing to worry: stack memory management is completely in the hands of the processor.
Instead, if the value is heap allocated, shadowing can be seen as a temporary memory leak that will be released at the end of the scope.
If this may be an issue we can explicitly free the memory with drop() before shadowing:
struct Foo {
_v: Vec<i32>
}
impl Drop for Foo {
fn drop(&mut self) {
println!("dropping foo");
}
}
fn main() {
println!("start");
let x = Foo {_v: vec![1,2,3]};
drop(x);
let x = 100;
println!("end");
}
Related
In Chapter 3 of the Rust Book, Variables and Mutability, we go through a couple iterations on this theme in order to demonstrate the default, immutable behavior of variables in Rust:
fn main() {
let x = 5;
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
Which outputs:
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:4:5
|
2 | let x = 5;
| -
| |
| first assignment to `x`
| help: make this binding mutable: `mut x`
3 | println!("The value of x is {}", x);
4 | x = 6;
| ^^^^^ cannot assign twice to immutable variable
However, because of Rust's take on shadowing variables, we can simply do this to change the value of the nonetheless "immutable" x:
fn main() {
let x = 5;
println!("The value of x is {}", x);
let x = 6;
println!("The value of x is {}", x);
}
Which outputs (skipping the details):
The value of x is 5
The value of x is 6
Funnily enough, this code also produces the above pair of lines as output, despite the fact that we don't call let but instead mut the first time x is bound to 5:
fn main() {
let mut x = 5;
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
This ambiguity in how variables are (not really) protected from reassignment seems contrary to the stated goal of protecting the values bound to immutable - by Rust default - variables. From the same chapter (which also contains the section Shadowing):
It’s important that we get compile-time errors when we attempt to
change a value that we previously designated as immutable because this
very situation can lead to bugs. If one part of our code operates on
the assumption that a value will never change and another part of our
code changes that value, it’s possible that the first part of the code
won’t do what it was designed to do. The cause of this kind of bug can
be difficult to track down after the fact, especially when the second
piece of code changes the value only sometimes.
In Rust, the compiler guarantees that when you state that a value
won’t change, it really won’t change. That means that when you’re
reading and writing code, you don’t have to keep track of how and
where a value might change. Your code is thus easier to reason
through.
If I can cause this important feature of my immutable x to be side-stepped with an innocent enough call to let, why do I need mut? Is there some way to really, seriously-you-guys make x immutable, such that no let x can reassign its value?
I believe the confusion is because you're conflating names with storage.
fn main() {
let x = 5; // x_0
println!("The value of x is {}", x);
let x = 6; // x_1
println!("The value of x is {}", x);
}
In this example, there is one name (x), and two storage locations (x_0 and x_1). The second let is simply re-binding the name x to refer to storage location x_1. The x_0 storage location is entirely unaffected.
fn main() {
let mut x = 5; // x_0
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
In this example, there is one name (x), and one storage location (x_0). The x = 6 assignment is directly changing the bits of storage location x_0.
You might argue that these do the same thing. If so, you would be wrong:
fn main() {
let x = 5; // x_0
let y = &x; // y_0
println!("The value of y is {}", y);
let x = 6; // x_1
println!("The value of y is {}", y);
}
This outputs:
The value of y is 5
The value of y is 5
This is because changing which storage location x refers to has absolutely no effect on the storage location x_0, which is what y_0 contains a pointer to. However,
fn main() {
let mut x = 5; // x_0
let y = &x; // y_0
println!("The value of y is {}", y);
x = 6;
println!("The value of y is {}", y);
}
This fails to compile because you cannot mutate x_0 while it is borrowed.
Rust cares about protecting against unwanted mutation effects as observed through references. This doesn't conflict with allowing shadowing, because you're not changing values when you shadow, you're just changing what a particular name means in a way that cannot be observed anywhere else. Shadowing is a strictly local change.
So yes, you absolutely can keep the value of x from being changed. What you can't do is keep what the name x refers to from being changed. At most, you can use something like clippy to deny shadowing as a lint.
I installed Rust 1.13 and tried:
fn main() {
let x: u32;
x = 10; // no error?
}
When I compiled this file there's some warnings, but there's no error. As I'm not declaring x as mut, shouldn't x = 10; cause an error?
What you have written is identical to:
let x: u32 = 10;
The compiler will not permit you to mutate it thereafter:
let x: u32;
x = 10;
x = 0; // Error: re-assignment of immutable variable `x`
Note that it is a compiler error if you try to use an uninitialized variable:
let x: u32;
println!("{}", x); // Error: use of possibly uninitialized variable: `x`
This feature can be pretty useful if you want to initialize the variable differently based on runtime conditions. A naive example:
let x: u32;
if condition {
x = 1;
} else if other_condition {
x = 10;
} else {
x = 100;
}
But still it will still be an error if there is a possibility that it isn't initialized:
let x: u32;
if condition {
x = 1;
} else if other_condition {
x = 10;
} // no else
println!("{:?}", x); // Error: use of possibly uninitialized variable: `x`
As mentioned, this is not mutation, but deferred initialization:
mutation is about changing the value of an existing variable,
deferred initialization is about declaring a variable at one point, and initializing it later.
The Rust compiler tracks whether a variable has a value at compile-time, so unlike C there is no risk of accidentally using an uninitialized variable (or unlike C++, a variable that was moved from).
The most important reason for using deferred initialization is scope.
fn main() {
let x;
let mut v = vec!();
{
x = 2;
v.push(&x);
}
println!("{:?}", v);
}
In Rust, the borrow-checker will validate that a reference cannot outlive the value it refers to, preventing dangling references.
This means that v.push(&x) requires that x lives longer than v, and therefore be declared before v.
The need for it does not crop up often, but when it does other solutions would require run-time checks.
Editor's note: This code example is from a version of Rust prior to 1.0 and is not syntactically valid Rust 1.0 code. Updated versions of this code produce different errors, but the answers still contain valuable information.
I would like to make an iterator that generates a stream of prime numbers. My general thought process was to wrap an iterator with successive filters so for example you start with
let mut n = (2..N)
Then for each prime number you mutate the iterator and add on a filter
let p1 = n.next()
n = n.filter(|&x| x%p1 !=0)
let p2 = n.next()
n = n.filter(|&x| x%p2 !=0)
I am trying to use the following code, but I can not seem to get it to work
struct Primes {
base: Iterator<Item = u64>,
}
impl<'a> Iterator for Primes<'a> {
type Item = u64;
fn next(&mut self) -> Option<u64> {
let p = self.base.next();
match p {
Some(n) => {
let prime = n.clone();
let step = self.base.filter(move |&: &x| {x%prime!=0});
self.base = &step as &Iterator<Item = u64>;
Some(n)
},
_ => None
}
}
}
I have toyed with variations of this, but I can't seem to get lifetimes and types to match up. Right now the compiler is telling me
I can't mutate self.base
the variable prime doesn't live long enough
Here is the error I am getting
solution.rs:16:17: 16:26 error: cannot borrow immutable borrowed content `*self.base` as mutable
solution.rs:16 let p = self.base.next();
^~~~~~~~~
solution.rs:20:28: 20:37 error: cannot borrow immutable borrowed content `*self.base` as mutable
solution.rs:20 let step = self.base.filter(move |&: &x| {x%prime!=0});
^~~~~~~~~
solution.rs:21:30: 21:34 error: `step` does not live long enough
solution.rs:21 self.base = &step as &Iterator<Item = u64>;
^~~~
solution.rs:15:39: 26:6 note: reference must be valid for the lifetime 'a as defined on the block at 15:38...
solution.rs:15 fn next(&mut self) -> Option<u64> {
solution.rs:16 let p = self.base.next();
solution.rs:17 match p {
solution.rs:18 Some(n) => {
solution.rs:19 let prime = n.clone();
solution.rs:20 let step = self.base.filter(move |&: &x| {x%prime!=0});
...
solution.rs:20:71: 23:14 note: ...but borrowed value is only valid for the block suffix following statement 1 at 20:70
solution.rs:20 let step = self.base.filter(move |&: &x| {x%prime!=0});
solution.rs:21 self.base = &step as &Iterator<Item = u64>;
solution.rs:22 Some(n)
solution.rs:23 },
error: aborting due to 3 previous errors
Why won't Rust let me do this?
Here is a working version:
struct Primes<'a> {
base: Option<Box<Iterator<Item = u64> + 'a>>,
}
impl<'a> Iterator for Primes<'a> {
type Item = u64;
fn next(&mut self) -> Option<u64> {
let p = self.base.as_mut().unwrap().next();
p.map(|n| {
let base = self.base.take();
let step = base.unwrap().filter(move |x| x % n != 0);
self.base = Some(Box::new(step));
n
})
}
}
impl<'a> Primes<'a> {
#[inline]
pub fn new<I: Iterator<Item = u64> + 'a>(r: I) -> Primes<'a> {
Primes {
base: Some(Box::new(r)),
}
}
}
fn main() {
for p in Primes::new(2..).take(32) {
print!("{} ", p);
}
println!("");
}
I'm using a Box<Iterator> trait object. Boxing is unavoidable because the internal iterator must be stored somewhere between next() calls, and there is nowhere you can store reference trait objects.
I made the internal iterator an Option. This is necessary because you need to replace it with a value which consumes it, so it is possible that the internal iterator may be "absent" from the structure for a short time. Rust models absence with Option. Option::take replaces the value it is called on with None and returns whatever was there. This is useful when shuffling non-copyable objects around.
Note, however, that this sieve implementation is going to be both memory and computationally inefficient - for each prime you're creating an additional layer of iterators which takes heap space. Also the depth of stack when calling next() grows linearly with the number of primes, so you will get a stack overflow on a sufficiently large number:
fn main() {
println!("{}", Primes::new(2..).nth(10000).unwrap());
}
Running it:
% ./test1
thread '<main>' has overflowed its stack
zsh: illegal hardware instruction (core dumped) ./test1
This may be a duplicate. I don't know. I couldn't understand the other answers well enough to know that. :)
Rust version: rustc 1.0.0-nightly (b47aebe3f 2015-02-26) (built 2015-02-27)
Basically, I'm passing a bool to this function that's supposed to build an iterator that filters one way for true and another way for false. Then it kind of craps itself because it doesn't know how to keep that boolean value handy, I guess. I don't know. There are actually multiple lifetime problems here, which is discouraging because this is a really common pattern for me, since I come from a .NET background.
fn main() {
for n in values(true) {
println!("{}", n);
}
}
fn values(even: bool) -> Box<Iterator<Item=usize>> {
Box::new([3usize, 4, 2, 1].iter()
.map(|n| n * 2)
.filter(|n| if even {
n % 2 == 0
} else {
true
}))
}
Is there a way to make this work?
You have two conflicting issues, so let break down a few representative pieces:
[3usize, 4, 2, 1].iter()
.map(|n| n * 2)
.filter(|n| n % 2 == 0))
Here, we create an array in the stack frame of the method, then get an iterator to it. Since we aren't allowed to consume the array, the iterator item is &usize. We then map from the &usize to a usize. Then we filter against a &usize - we aren't allowed to consume the filtered item, otherwise the iterator wouldn't have it to return!
The problem here is that we are ultimately rooted to the stack frame of the function. We can't return this iterator, because the array won't exist after the call returns!
To work around this for now, let's just make it static. Now we can focus on the issue with even.
filter takes a closure. Closures capture any variable used that isn't provided as an argument to the closure. By default, these variables are captured by reference. However, even is again a variable located on the stack frame. This time however, we can give it to the closure by using the move keyword. Here's everything put together:
fn main() {
for n in values(true) {
println!("{}", n);
}
}
static ITEMS: [usize; 4] = [3, 4, 2, 1];
fn values(even: bool) -> Box<Iterator<Item=usize>> {
Box::new(ITEMS.iter()
.map(|n| n * 2)
.filter(move |n| if even {
n % 2 == 0
} else {
true
}))
}
I'm modeling an algorithm in Spin.
I have a process that has several channels and at some point, I know a message is going to come but don't know from which channel. So want to wait (block) the process until it a message comes from any of the channels. how can I do that?
I think you need Promela's if construct (see http://spinroot.com/spin/Man/if.html).
In the process you're referring to, you probably need the following:
byte var;
if
:: ch1?var -> skip
:: ch2?var -> skip
:: ch3?var -> skip
fi
If none of the channels have anything on them, then "the selection construct as a whole blocks" (quoting the manual), which is exactly the behaviour you want.
To quote the relevant part of the manual more fully:
"An option [each of the :: lines] can be selected for execution only when its guard statement is executable [the guard statement is the part before the ->]. If more than one guard statement is executable, one of them will be selected non-deterministically. If none of the guards are executable, the selection construct as a whole blocks."
By the way, I haven't syntax checked or simulated the above in Spin. Hopefully it's right. I'm quite new to Promela and Spin myself.
If you want to have your number of channels variable without having to change the implementation of the send and receive parts, you might use the approach of the following producer-consumer example:
#define NUMCHAN 4
chan channels[NUMCHAN];
init {
chan ch1 = [1] of { byte };
chan ch2 = [1] of { byte };
chan ch3 = [1] of { byte };
chan ch4 = [1] of { byte };
channels[0] = ch1;
channels[1] = ch2;
channels[2] = ch3;
channels[3] = ch4;
// Add further channels above, in
// accordance with NUMCHAN
// First let the producer write
// something, then start the consumer
run producer();
atomic { _nr_pr == 1 ->
run consumer();
}
}
proctype consumer() {
byte var, i;
chan theChan;
i = 0;
do
:: i == NUMCHAN -> break
:: else ->
theChan = channels[i];
if
:: skip // non-deterministic skip
:: nempty(theChan) ->
theChan ? var;
printf("Read value %d from channel %d\n", var, i+1)
fi;
i++
od
}
proctype producer() {
byte var, i;
chan theChan;
i = 0;
do
:: i == NUMCHAN -> break
:: else ->
theChan = channels[i];
if
:: skip;
:: theChan ! 1;
printf("Write value 1 to channel %d\n", i+1)
fi;
i++
od
}
The do loop in the consumer process non-deterministically chooses an index between 0 and NUMCHAN-1 and reads from the respective channel, if there is something to read, else this channel is always skipped. Naturally, during a simulation with Spin the probability to read from channel NUMCHAN is much smaller than that of channel 0, but this does not make any difference in model checking, where any possible path is explored.