fn test<T>(t: T) {
println!("size of: {}", std::mem::size_of::<T>());
}
fn main() {
let f = || {
let i1: i32 = 0;
let i2: i32 = 0;
let i3: i32 = 0;
i1 + i2 + i3
};
test(f) // prints "size of: 0"
}
A non move closure always seems to prints that the size is 0 probably because it is just inlined.
A move closure gets bigger with every variable that it captures but I wonder if it is possible to query the stack space that a closure requires?
Update:
I want to create something like a Coroutine<F>. I need to know the size of F for it to be executed. I currently allocate 1mb per coroutine which is way too much. So I was wondering if it would be possible to determine the actual size that I need to allocate.
I misunderstood the question, so the following text does not really answer OP's question!
Yes, you can measure the size of a closure. The sizes are just a bit confusing sometimes. Let's test all kinds of closures:
let constant = || 27;
let no_capture = |x: i32| 27 + x;
let a = vec![3];
let immut_capture = || a[0] + 27;
let immut_capture_arg = |x: i32| a[0] + x;
let mut b = vec![3];
let mut c = vec![3];
let mut_capture = || { b[0] += 27; b[0] };
let mut_capture_arg = |x: i32| { c[0] += x; c[0] };
let mut d = vec![3];
let mut e = vec![3];
let move_capture = move || { d[0] += 27; d.into_boxed_slice() };
let move_capture_arg = move |x: i32| { e[0] += x; e.into_boxed_slice() };
When I print their sizes with std::mem::size_of_val (which is roughly equivalent to your hand-written test() function), I get the following results:
constant -> 0
no_capture -> 0
immut_capture -> 8
immut_capture_arg -> 8
mut_capture -> 8
mut_capture_arg -> 8
move_capture -> 24
move_capture_arg -> 24
You can try it yourself with this code on playground.
So whats up with those results?
A closure is a type that saves its environment – either by reference or by value. Mutable and immutable reference to sized data have the same size, namely size_of::<usize>(), usually 8. This explains the size of the closures that capture the outer variable by reference.
The move closures on the other hand, capture their environment by value, which means that they have to save the environment inside themselves. So it's no surprise that their sizes are equal to size_of::<Vec<_>>().
What about the closures with size 0? Since they are not capturing any environment, they could be ordinary fn-functions, too. And I guess that Rust turns them into fn-functions. And in fact, if we try to print the size of an fn-item (not a function pointer!) like this:
fn foo(x: i32) -> i32 { x + 27 }
println!("{}", std::mem::size_of_val(&foo));
... we get 0!
Related
In Rust, in order to change the value of a mutable variable, what is the difference in let x = 12 or x = 12 in the following sample code?
fn main() {
let mut x: i32 = 8;
{
println!("{}", x);
let x = 12; // what if change to x = 12
println!("{}", x);
}
println!("{}", x);
let x = 42;
println!("{}", x);
}
The output is 8, 12, 8, 42. If I change let x = 12 to x = 12 ...
fn main() {
let mut x: i32 = 8;
{
println!("{}", x);
x = 12;
println!("{}", x);
}
println!("{}", x);
let x = 42;
println!("{}", x);
}
The output is 8, 12, 12, 42.
I understand that Rust uses let to do variable binding, so the let x = 12 is a variable rebinding and the binding is only valid inside a scope. But how to explain the functionality of x = 12 and the corresponding scope? Is that a type of variable binding?
The second let x introduces a second binding that shadows the first one for the rest of the block. That is, there are two variables named x, but you can only access the second one within the block statement after the let x = 12; statement. These two variables don't need to have the same type!
Then, after the block statement, the second x is out of scope, so you access the first x again.
However, if you write x = 12; instead, that's an assignment expression: the value in x is overwritten. This doesn't introduce a new variable, so the type of the value being assigned must be compatible with the variable's type.
This difference is important if you write a loop. For example, consider this function:
fn fibonacci(mut n: u32) -> u64 {
if n == 0 {
return 1;
}
let mut a = 1;
let mut b = 1;
loop {
if n == 1 {
return b;
}
let next = a + b;
a = b;
b = next;
n -= 1;
}
}
This function reassigns variables, so that each iteration of the loop can operate on the values assigned on the preceding iteration.
However, you might be tempted to write the loop like this:
loop {
if n == 1 {
return b;
}
let (a, b) = (b, a + b);
n -= 1;
}
This doesn't work, because the let statement introduces new variables, and these variables will go out of scope before the next iteration begins. On the next iteration, (b, a + b) will still use the original values.
In Rust, in order to change the value of a mutable variable, what is the difference in let x = 12 or x = 12 in the following sample code?
fn main() {
let mut x: i32 = 8;
{
println!("{}", x);
let x = 12; // what if change to x = 12
println!("{}", x);
}
println!("{}", x);
let x = 42;
println!("{}", x);
}
The output is 8, 12, 8, 42. If I change let x = 12 to x = 12 ...
fn main() {
let mut x: i32 = 8;
{
println!("{}", x);
x = 12;
println!("{}", x);
}
println!("{}", x);
let x = 42;
println!("{}", x);
}
The output is 8, 12, 12, 42.
I understand that Rust uses let to do variable binding, so the let x = 12 is a variable rebinding and the binding is only valid inside a scope. But how to explain the functionality of x = 12 and the corresponding scope? Is that a type of variable binding?
The second let x introduces a second binding that shadows the first one for the rest of the block. That is, there are two variables named x, but you can only access the second one within the block statement after the let x = 12; statement. These two variables don't need to have the same type!
Then, after the block statement, the second x is out of scope, so you access the first x again.
However, if you write x = 12; instead, that's an assignment expression: the value in x is overwritten. This doesn't introduce a new variable, so the type of the value being assigned must be compatible with the variable's type.
This difference is important if you write a loop. For example, consider this function:
fn fibonacci(mut n: u32) -> u64 {
if n == 0 {
return 1;
}
let mut a = 1;
let mut b = 1;
loop {
if n == 1 {
return b;
}
let next = a + b;
a = b;
b = next;
n -= 1;
}
}
This function reassigns variables, so that each iteration of the loop can operate on the values assigned on the preceding iteration.
However, you might be tempted to write the loop like this:
loop {
if n == 1 {
return b;
}
let (a, b) = (b, a + b);
n -= 1;
}
This doesn't work, because the let statement introduces new variables, and these variables will go out of scope before the next iteration begins. On the next iteration, (b, a + b) will still use the original values.
I have a HashMap<i8, i8> which could contain cycles:
let mut x: HashMap<i8, i8> = HashMap::new();
x.insert(1, 6);
x.insert(3, 5);
x.insert(5, 1);
To get the final value for 3, it should first lookup x[3], then x[5] and finally x[1] which should yield 6. I decided to use a while let loop:
let mut y = x[&3]; // y: i8
while let Some(&z) = x.get(&y) {
y = z;
}
println!("{}", y);
x.insert(0, 0);
This works fine, but it would panic! if 3 is not in the map. As I don't want to do anything about the None case, I want to use a if let (similar to the while let used).
I have tried some notations:
if let Some(&y) = x.get(&3): copies the value, but y is immutable (y: i8)
if let Some(mut y) = x.get(&3): y is mutable, but the value is borrowed (mut y: &i8)
if let mut Some(&y) = x.get(&3): my target: mutable copy, but invalid syntax (mut y: i8)
(All variants are available at Rust Playground, but you need to comment out the third try, as it is invalid syntax)
I would not argue about the second variant, but I need to insert values into my map in the body of the if let. As the map remains borrowed, I can't insert anymore. All I would need is that the value in Some(y) is copied, and y is mutable, so that the borrow checker is satisfied and I can do my recursive lookups.
Your approach #1 is a perfectly correct match, you just need to make the y variable mutable. One possibility is to convert Option<&i8> to Option<i8>, enabling the use of mut y in the pattern. For example, Option::map can dereference the value:
if let Some(mut y) = x.get(&3).map(|ref| *ref) {
Since Copy implies (cheap) Clone, you can express the same using Option::cloned():
if let Some(mut y) = x.get(&3).cloned() {
As of Rust 1.35, you can use Option::copied(), which is only defined for Copy types and just copies the value:
if let Some(mut y) = x.get(&3).copied() {
Another possibility is to leave your approach #1 as-is, but correct it simply by introducing a separate mutable variable inside the if let block:
if let Some(&y) = x.get(&3) {
let mut y = y;
...
Your code basically works:
use std::collections::HashMap;
fn main() {
let mut x: HashMap<i8, i8> = HashMap::new();
x.insert(1, 6);
x.insert(3, 5);
x.insert(5, 1);
let mut key = 3;
while let Some(&z) = x.get(&key) {
key = z;
}
println!("{}", key);
x.insert(key, 0);
}
Here, key is left as the last key that did not match.
I've been trying to rewrite the code below for summing floating point numbers while minimizing the rounding errors, but I found it pretty hard to do in Rust. Any suggestions would be greatly appreciated. I attach my non-working Rust attempt
def msum(iterable):
"Full precision summation using multiple floats for intermediate values"
# Rounded x+y stored in hi with the round-off stored in lo. Together
# hi+lo are exactly equal to x+y. The inner loop applies hi/lo summation
# to each partial so that the list of partial sums remains exact.
# Depends on IEEE-754 arithmetic guarantees. See proof of correctness at:
#www-2.cs.cmu.edu/afs/cs/project/quake/public/papers/robust-arithmetic.ps
partials = [] # sorted, non-overlapping partial sums
for x in iterable:
i = 0
for y in partials:
if abs(x) < abs(y):
x, y = y, x
hi = x + y
lo = y - (hi - x)
if lo:
partials[i] = lo
i += 1
x = hi
partials[i:] = [x]
return sum(partials, 0.0)
The code below is what I have in Rust so far, but it's not working yet
fn inexact_sum(v: &Vec<f64>) -> f64 {
let mut partials: Vec<f64> = vec![];
for x in v {
let mut i: usize = 0;
let mut hi: f64;
let mut lo: f64;
for y in partials.clone().iter() {
hi = x + y;
lo = if x.abs() < y.abs() {
y - (hi - x)
} else {
x - (hi - y)
};
if lo != 0.0_f64 {
partials[i] = lo;
i += 1;
}
let x = hi;
println!("x = {}, y = {}", x, y);
}
partials.truncate(i);
partials.push(hi);
}
partials.iter().fold(0.0_f64, |a, b| a + b)
}
EDIT: Thinking about it a bit more, indeed, the error the compiler gave me error: use of possibly uninitialized variable: `hi` is indeed useful. I should have paid more attention to it. The point is that the first time the loop does not execute at all, so hi does not get initialized. So if I change partials.push(hi); to partials.push(*x); the code compiles and runs but it does not give the right answer.
Is this what you are looking for? I think you did not mean to clone the partials array but found that you needed to in order to satisfy the borrow checker; if you try to use the code:
for y in partials.iter() {
...
partials[i] = lo;
The borrow checker will complain:
<anon>:13:17: 13:25 error: cannot borrow `partials` as mutable because it is also borrowed as immutable [E0502]
I got around this by using an index into the array instead:
for j in 0..partials.len() {
let mut y = partials[j];
Then you are not cloning the whole array of partials each time around the outer loop! Since the partials array can be modified whilst iterating through it, taking a clone first means you will end up with the old value of y instead of the new one if it has been modified.
use std::mem;
fn msum(v: &[f64]) -> f64 {
let mut partials: Vec<f64> = vec![];
for x in v {
let mut x = *x;
let mut i = 0;
for j in 0..partials.len() {
let mut y = partials[j];
if x.abs() < y.abs() { mem::swap(&mut x, &mut y) }
let hi = x + y;
let lo = y - (hi - x);
if lo != 0.0 {
partials[i] = lo;
i += 1;
}
x = hi;
}
partials.truncate(i);
partials.push(x);
}
partials.iter().fold(0., |a, b| a + b)
}
fn main() {
let v = vec![1.234, 1e16, 1.234, -1e16];
println!("{}",msum(&v));
}
Playpen
Editor's note: this question was asked before Rust 1.0 and some of the assertions in the question are not necessarily true in Rust 1.0. Some answers have been updated to address both versions.
I want to create a vector, but I only know the size I want the vector to be at runtime. This is how I'm doing it now (i.e. creating an empty, mutable vector, and adding vectors to it) :
fn add_pairs(pairs: ~[int]) -> ~[int] {
let mut result : ~[int] = ~[];
let mut i = 0;
while i < pairs.len() {
result += ~[pairs[i] + pairs[i + 1]];
i += 2;
}
return result;
}
This is how I want to do it (i.e., creating a vector and putting everything in it, instead of adding lots of vectors together):
fn add_pairs(pairs: ~[int]) -> ~[int] {
let number_of_pairs = pairs.len() / 2;
let result : ~[int, ..number_of_pairs];
let mut i = 0;
while i < pairs.len() {
result[i] = pairs[2 * i] + pairs[2 * i + 1];
i += 1;
}
return result;
}
Unfortunately, doing the above gives me something like:
error: expected constant expr for vector length: Non-constant path in constant expr
let result: ~[int, ..number_of_pairs];
^~~~~~~~~~~~~~~~~~~~~~~~
I get the impression that vectors have to have their size known at compile time (and so you need to set their size to a constant). Coming from a Java background, I'm confused! Is there a way to create a vector whose size you only know at runtime?
I'm using Rust 0.6.
In Rust version 1.0.0, they've made the std::vec:Vec public structure stable so that you can instantiate a growable vector with let mut my_vec = Vec::new(); You can also use the vec! macro like so: let mut another_vec = vec![1isize, 2isize, 3isize]; What is important to note is that in both cases the variable you're assigning must be mutable.
With these vectors you can call my_vec.push(num); for individual items or another_vec.extend_from_slice(["list", "of", "objects"]); to add items to the end of the vector.
For your specific problem, you could do something like this:
fn add_pairs(pairs: Vec<(Vec<isize>)>) -> Vec<isize> {
let mut result = Vec::new();
for pair in pairs.iter() {
result.push(pair[0]);
result.push(pair[1]);
}
return result;
}
You can see this in action on the Rust Playground where you have (what I assumed) was a nested vector of integer pairs.
There is no way to create an array of constant length with the length determined at runtime; only compile-time constant length arrays are allowed, so (variations of) your first method with Vec<i32> (previously ~[int]) is the only supported way. You could use vec![0; number_of_pairs] to create a vector of the correct size and use the second part.
There are many helper functions for what you are trying to do (using while directly Rust should be very rare):
fn add_pairs(pairs: &[i32]) -> Vec<i32> {
let mut result = Vec::new();
for i in 0..(pairs.len() / 2) {
result.push(pairs[2 * i] + pairs[2 * i + 1])
}
result
}
Or even
fn add_pairs(pairs: &[i32]) -> Vec<i32> {
pairs
.chunks(2)
.filter(|x| x.len() == 2)
.map(|x| x[0] + x[1])
.collect()
}
Docs: chunks, filter, map, collect. (The filter is just because the last element of chunks may have length 1.)
Also note that adding two vectors allocates a whole new one, while push doesn't do this necessarily and is much faster (and .collect is similar).
In at least Rust 1.0, there is a Vec::with_capacity() function that handles this scenario.
Example code:
let n = 44; // pretend this is determined at run time
let mut v = Vec::<f64>::with_capacity(n);
v.push(6.26);
println!("{:?}", v); // prints [6.26]
println!("{:?}", v.len()); // prints 1
println!("{:?}", v.capacity()); // prints 44