Why does the compiler warn about an uninitialized variable even though I've assigned each field of that variable? - initialization

I'm completely assigning the fields of the MyStruct instance named x in every possible brace of the match:
enum MyEnum {
One,
Two,
Three,
}
struct MyStruct {
a: u32,
b: u32,
}
fn main() {
f(MyEnum::One);
f(MyEnum::Two);
f(MyEnum::Three);
}
fn f(y: MyEnum) -> MyStruct {
let mut x: MyStruct;
match y {
MyEnum::One => {
x.a = 1;
x.b = 1;
}
MyEnum::Two => {
x.a = 2;
x.b = 2;
}
MyEnum::Three => {
x.a = 3;
x.b = 3;
}
}
x
}
Why does the compiler return the following error?
error[E0381]: use of possibly uninitialized variable: `x`
--> src/main.rs:37:5
|
37 | x
| ^ use of possibly uninitialized `x`
I think this is a known issue (see also its related issue).

let x: MyStruct; doesn't set x to an empty value, it declares a variable. You still need to assign a value to it.
fn f(y: MyEnum) -> MyStruct {
let x;
match y {
MyEnum::One => {
x = MyStruct { a: 1, b: 1 };
}
MyEnum::Two => {
x = MyStruct { a: 2, b: 2 };
}
MyEnum::Three => {
x = MyStruct { a: 3, b: 3 };
}
}
x
}
In other words, let x; creates an unbound variable, a variable which doesn't have a value associated with it. Thus you need to bind some value to it later.
If you only want to return a value from the function, you can take advantage of the fact that almost every statement in Rust produces a value, and a value of the last statement is the return value of a function.
fn f(y: MyEnum) -> MyStruct {
use MyEnum::*;
let x = match y {
One => MyStruct { a: 1, b: 1 },
Two => MyStruct { a: 2, b: 2 },
Three => MyStruct { a: 3, b: 3 },
};
x
}
You can also completely eliminate x, if you so choose.
fn f(y: MyEnum) -> MyStruct {
use MyEnum::*;
match y {
One => MyStruct { a: 1, b: 1 },
Two => MyStruct { a: 2, b: 2 },
Three => MyStruct { a: 3, b: 3 },
}
}

Related

Using fold together with enumerate to find max values in a selection of elements of a flattened vector

I am learning Rust and came upon a problem that I can easily solve by using nested loops with conditions. Unfortunately I fail miserably when trying to rewrite it using more idiomatic rust by the use of iterators and and things like fold, filter and flatten.
I have a vector of vectors of structs. Each struct has an identifier and a value. For each possible identifier I want to find the maximum value and return everything in a new vec of max values. The code below works fine.
struct MyStruct {
id: usize,
value: usize,
}
fn main() {
let vecvec_of_structs = vec![
vec![
MyStruct { id: 2, value: 1 },
MyStruct { id: 1, value: 15 },
MyStruct { id: 0, value: 31 },
],
vec![
MyStruct { id: 3, value: 10 },
MyStruct { id: 4, value: 25 },
MyStruct { id: 0, value: 150 },
MyStruct { id: 2, value: 150 },
],
];
let groups = 5;
let mut max_values_by_id: Vec<usize> = vec![0; groups];
// iterate over group_ids, in structs with respective group_id to find max value associated with it.
for id in 0..groups {
for vec_of_structs in &vecvec_of_structs {
for s in vec_of_structs {
if s.id == id {
if max_values_by_id[id] < s.value {
max_values_by_id[id] = s.value
};
}
}
}
}
println!("{:?}", max_values_by_id);
}
Now I tried to rewrite it like the piece below, that I am stuck with and which doesn't work. I don't know how to combine the different pieces. Or maybe they are not supposed to fit together in the first place.
let max_delay: Vec<usize> = max_values_by_node
.iter()
.enumerate()
.fold(0, |max_value, i| {
&vecvec_of_structs
.into_iter()
.flatten()
.filter(|e| e.id == i)
.max_by_key(|e| e.value)
.unwrap()
.value
})
.collect();
I would do something like this.
I start from the end: we want to collect five numbers.
For each of them considered as an id, we have have to iterate over all the structs: map() + iter() + flatten()
For each struct, we are only interested in the specific id, then we get its value: filter_map()
These values, if any, have to be folded.
let max_delay: Vec<usize> = (0..5)
.map(|i| {
vecvec_of_structs
.iter()
.flatten()
.filter_map(|s| if s.id == i { Some(s.value) } else { None })
.fold(0, |acc, value| acc.max(value))
})
.collect();

Ramda applySpec - keep unmodified props

Let's say I have an object const foo = { a: 1, b: 2 } and I want to add a prop c which is based on b.
I could do:
applySpec({
a: prop('a'),
b: prop('b'),
c: ({ b }) => b + 1
}, foo)
and get an object like: { a: 1, b: 2, c: 3 }
Is there a nicer way to do this?
I've looked at evolve, assoc and applySpec but none of them seems to be fit for purpose.
You can use R.chain to create a function that apply the spec, and then merges the new object with the original one.
If R.chain is used with function (f & g):
chain(f, g)(x) is equivalent to f(g(x), x)
In this case chain(mergeLeft, applySpec({})) is equal to mergeLeft(applySpec({}), originalObject).
const { chain, mergeLeft, applySpec } = R
const fn = chain(mergeLeft, applySpec({
c: ({ b }) => b + 1
}))
const foo = { a: 1, b: 2 }
const result = fn(foo)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
You can make this a generic function that allows adding to existing object, by using R.pipe to pass a curried R.applySpec to the chain:
const { pipe, chain, mergeLeft, applySpec } = R
const fn = pipe(applySpec, chain(mergeLeft))
const addCProp = fn({
c: ({ b }) => b + 1
})
const foo = { a: 1, b: 2 }
const result = addCProp(foo)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>

What is the correct pattern for a vector of structs where each struct contains a subset of an array of structs?

I've got code very similar to the following (my filter function is more complex though):
struct MyStruct {
a: i32,
b: i32,
count: i32,
}
impl MyStruct {
fn filter(&self) -> bool {
return self.a > self.b + self.count;
}
}
struct ContainerStruct<'a> {
x: i32,
v: Vec<&'a MyStruct>,
}
fn main() {
let mut list_of_items = vec![
MyStruct {
a: 1,
b: 2,
count: 0,
},
MyStruct {
a: 2,
b: 1,
count: 0,
},
MyStruct {
a: 5,
b: 2,
count: 0,
},
];
let mut count = 0;
let mut list_of_containers: Vec<ContainerStruct> = Vec::new();
while count < 10 {
let mut c = ContainerStruct {
x: 1,
v: Vec::new(),
};
for i in list_of_items.iter_mut() {
i.count = count;
if i.filter() {
c.v.push(i);
}
}
count += 1;
list_of_containers.push(c)
}
}
Which does not compile, due to the following error:
error[E0499]: cannot borrow `list_of_items` as mutable more than once at a time
--> src/main.rs:43:18
|
43 | for i in list_of_items.iter_mut() {
| ^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
I know this is a borrow-checking issue, and I can see the potential problems with references etc. What I don't know is the correct pattern to use to achieve what I'm looking for, which is essentially a vector of structs, where each struct contains a subset of an array of structs.
I need to be able to mutate the structs, so I'm forced into using iter_mut().
However that moves the vector into that scope which then gets released next time I go through the external while loop.
Is there any way to force the vector to live long enough to complete the outer loop? I thought about copying the structs but I don't want to do that. I only need references to each one and copying would introduce an unacceptable overhead due to the size of the vector in question.
This compiles:
use std::cell::Cell;
struct MyStruct {
a: i32,
b: i32,
count: Cell<i32>,
}
impl MyStruct {
fn filter(&self) -> bool {
return self.a > self.b + self.count.get();
}
}
struct ContainerStruct<'a> {
x: i32,
v: Vec<&'a MyStruct>,
}
fn main() {
let mut list_of_items = vec![
MyStruct {
a: 1,
b: 2,
count: Cell::new(0),
},
MyStruct {
a: 2,
b: 1,
count: Cell::new(0),
},
MyStruct {
a: 5,
b: 2,
count: Cell::new(0),
},
];
let mut count = 0;
let mut list_of_containers: Vec<ContainerStruct> = Vec::new();
while count < 10 {
let mut c = ContainerStruct {
x: 1,
v: Vec::new(),
};
for i in list_of_items.iter() {
i.count.set(count);
if i.filter() {
c.v.push(i);
}
}
count += 1;
list_of_containers.push(c)
}
}

How do I create a macro that takes a function with multiple parameters and supplies the first argument for that function?

I want to be able to create a higher-order function (called g) that takes in a function (called f). g should pass in the first parameter to f and return a new function.
The use case is that I want to initiate a database connection in g and pass it functions that accept a database connection.
fn f1(a: i32, b: String) -> String {
b
}
fn f2(a: i32, c: i64, d: i16) -> i32 {
1000
}
fn g<T>(f: fn(a: i32, arbitrary_arguments_type) -> T) -> fn(arbitrary_arguments_type) -> T {
move |arbitrary_arguments| f(1, arbitrary_arguments)
}
fn main() {
g(f1)("hello".to_string());
g(f2)(10, 11);
}
How do I create a macro that takes in as an argument a function with a more than 1 parameter, where first parameter is of a certain type, and supplies that argument for that first function?
The specific question I'm having is how do I create a macro that takes in as an argument a function with a more than 1 parameter, where first parameter is of a certain type, supplies that argument for that first function.
Macros (even procedural macros) operate on syntax trees, so they can't change their behaviour based on semantics, including types and function arity. That means you'd have to have a different macro for each possible number of arguments. For example:
macro_rules! curry1 {
($func: ident, $($arg: expr),*) => {
|a| $func($($arg),*, a)
}
}
macro_rules! curry2 {
($func: ident, $($arg: expr),*) => {
|a, b| $func($($arg),*, a, b)
}
}
macro_rules! curry3 {
($func: ident, $($arg: expr),*) => {
|a, b, c| $func($($arg),*, a, b, c)
}
}
Which would be used like this:
fn f(a: i32, b: i32, c: i32) -> i32 {
a + b + c
}
fn main() {
// requires 2 extra args
let f_2 = curry2!(f, 2);
// requires 1 extra arg
let f_2_1 = curry1!(f, 2, 1);
println!("{}", f(2, 1, 3)); // 6
println!("{}", f_2(1, 3)); // 6
println!("{}", f_2_1(3)); // 6
}

Most efficient way to fill a vector from back to front

I am trying to populate a vector with a sequence of values. In order to calculate the first value I need to calculate the second value, which depends on the third value etc etc.
let mut bxs = Vec::with_capacity(n);
for x in info {
let b = match bxs.last() {
Some(bx) => union(&bx, &x.bbox),
None => x.bbox.clone(),
};
bxs.push(b);
}
bxs.reverse();
Currently I just fill the vector front to back using v.push(x) and then reverse the vector using v.reverse(). Is there a way to do this in a single pass?
Is there a way to do this in a single pass?
If you don't mind adapting the vector, it's relatively easy.
struct RevVec<T> {
data: Vec<T>,
}
impl<T> RevVec<T> {
fn push_front(&mut self, t: T) { self.data.push(t); }
}
impl<T> Index<usize> for RevVec<T> {
type Output = T;
fn index(&self, index: usize) -> &T {
&self.data[self.len() - index - 1]
}
}
impl<T> IndexMut<usize> for RevVec<T> {
fn index_mut(&mut self, index: usize) -> &mut T {
let len = self.len();
&mut self.data[len - index - 1]
}
}
The solution using unsafe is below. The unsafe version is slightly more than 2x as fast as the safe version using reverse(). The idea is to use Vec::with_capacity(usize) to allocate the vector, then use ptr::write(dst: *mut T, src: T) to write the elements into the vector back to front. offset(self, count: isize) -> *const T is used to calculate the offset into the vector.
extern crate time;
use std::fmt::Debug;
use std::ptr;
use time::PreciseTime;
fn scanl<T, F>(u : &Vec<T>, f : F) -> Vec<T>
where T : Clone,
F : Fn(&T, &T) -> T {
let mut v = Vec::with_capacity(u.len());
for x in u.iter().rev() {
let b = match v.last() {
None => (*x).clone(),
Some(y) => f(x, &y),
};
v.push(b);
}
v.reverse();
return v;
}
fn unsafe_scanl<T, F>(u : &Vec<T> , f : F) -> Vec<T>
where T : Clone + Debug,
F : Fn(&T, &T) -> T {
unsafe {
let mut v : Vec<T> = Vec::with_capacity(u.len());
let cap = v.capacity();
let p = v.as_mut_ptr();
match u.last() {
None => return v,
Some(x) => ptr::write(p.offset((u.len()-1) as isize), x.clone()),
};
for i in (0..u.len()-1).rev() {
ptr::write(p.offset(i as isize), f(v.get_unchecked(i+1), u.get_unchecked(i)));
}
Vec::set_len(&mut v, cap);
return v;
}
}
pub fn bench_scanl() {
let lo : u64 = 0;
let hi : u64 = 1000000;
let v : Vec<u64> = (lo..hi).collect();
let start = PreciseTime::now();
let u = scanl(&v, |x, y| x + y);
let end= PreciseTime::now();
println!("{:?}\n in {}", u.len(), start.to(end));
let start2 = PreciseTime::now();
let u = unsafe_scanl(&v, |x, y| x + y);
let end2 = PreciseTime::now();
println!("2){:?}\n in {}", u.len(), start2.to(end2));
}

Resources