Initialize two struct members with a function that returns a tuple in Rust - struct

So I have a function that returns a tuple of 2 values, and I want to assign these values to two different members of a struct. Is there a way to do this without having to call the function twice and extract each value individually?
I'm thinking something like:
let mut my_struct : MyStruct = MyStruct {
(member1, member2): function_that_returns_tuple()
}
Currently I am calling the function on two temporary variables and then moving them to the struct members but I'm wondering if there's a way to do it directly in the initialization.

I believe that your existing approach is the correct one. If you name the variables as the struct members, you can avoid the explicit member: value syntax:
let (member1, member2) = function_that_returns_tuple();
MyStruct { member1, member2, }

Related

Storing mutable references owned by someone else

I want to store structs in HashMap but also reference to same structs inside another struct vector field.
Let's say I have a tree build of two types of structs Item and Relation.
I am storing all the relations in HashMap by their id,
but I also want to fill each item.out_relations vector with mutable references to same Relation structs which are owned by HashMap.
Here is my Item:
pub struct Item<'a> {
pub id: oid::ObjectId,
pub out_relations: Vec<&'a mut Relation>, // <-- want to fill this
}
And when I am iterating over my relations got from DB
I am trying to do smth like this:
let from_id = relation.from_id; //to find related item
item_map // my items loaded here already
.entry(from_id)
.and_modify(|item| {
(*item)
.out_relations.push(
relation_map.try_insert(relation.id, relation).unwrap() // mut ref to relation expected here
)
}
);
For now compiler warns try_insert is unstable feature and points me to this bug
But let's imagine I have this mutable ref to relation owned already by HashMap- is it going to work?
Or this will be again some ref lives not long enough error? What are my options then? Or I better will store just relation id in item out_relations vector rather then refs? And when needed I will take my relation from the hashmap?
This is called shared mutability, and it is forbidden by the borrow checker.
Fortunately Rust offers safe tools to achieve this.
In your case you need to use Rc<RefCell>, so your code would be:
pub struct Item {
pub id: oid::ObjectId,
pub out_relations: Vec<Rc<RefCell<Relation>>>,
}
And when I am iterating over my relations got from DB I am trying to do smth like this:
let relation = Rc::new(RefCell::new(relation));
let from_id = relation.borrow().from_id; // assuming id is a Copy type
item_map // my items loaded here already
.entry(from_id)
.and_modify(|item| {
(*item)
.out_relations.push(
relation_map.try_insert(relation.id, relation.clone()).unwrap() // mut ref to relation expected here
)
}
);
If you want to mutate relation later, you can use .borrow_mut()
relation.borrow_mut().from_id = new_id;
I agree with Oussama Gammoudi's diagnosis, but I'd like to offer alternative solutions.
The issue with reference counting is that it kills performance.
In your vector, can you store the key to the hash map instead? Then, when you need to get the value from the vector, get the key from the vector and fetch the value from the hash map?
Another strategy is to keep a vector of the values, and then store indices into the vector in your hash map and other vector. This Rust Keynote speaker describes the strategy well: https://youtu.be/aKLntZcp27M?t=1787

create and return struct in declarative macro

Back here with learning macros,
I'm wondering if a macro can generate a struct and return it.
I'm trying to iterate over multiple components in a ecs. I've managed to write the functions to iterate over one component type, and over all pairs of components, in a way that could be expanded to any number of component types.
So now, I want to make a macro that automate the process. The macro should :
create a struct that will be the iterator, and that will be returned
implement the Iterator trait on that struct
build an instance of that struct and return it.
you can see On the git page the implementations of the iterator, the structs, and the functions for 1 and 2 components, and they can be super easily extended (at the end of the file).
Here is what I'm trying for now :
#[macro_export]
macro_rules! iterate_over_component {
($ecs:expr; $($comp:ty),+) => {
// create the result struct that will act as an iterator
struct ComponentIterator<$($comp),+> {
current_iterator: usize,
current_entity: usize,
$(
array_$comp: Option<&'a Vec<IndexedElem<$comp>>>,
current_index_$comp: usize,
)*
}
};
}
But I'm having lots of issues :
It doesn't seems the ty keyword accepts types ? I would like to call the macro like so : iterate_over_component!(ecs; Position, Velocity) (where Position and Velocity are structs types)
I'm having errors when using the struct keyword at the beginning of the macro, so can I really declare structs in there ?

What is a memory-efficient type for a map with no meaningful value in Rust?

In Go, a memory-efficient way of storing values you want to retrieve by key that has no associated value is to use a map of empty structs keyed with the data you want to store. For instance, if you have a list of strings you want to check have been previously seen by your program, you could do something like this:
var seen = map[string]struct{}{}
for _, str := range strings {
if _, ok := seen[str]; ok {
// do something
} else {
seen[str] = struct{}{}
}
}
Is there a Rust equivalent to this? I am aware that Rust doesn't have anonymous structs like Go, so what Rust type would use the least amount of memory in a map like the above example? Or is there a different, more idiomatic approach?
A HashSet is defined as a HashMap with the unit tuple as the value:
pub struct HashSet<T, S = RandomState> {
map: HashMap<T, (), S>,
}
The same is true for BTreeSet / BTreeMap:
pub struct BTreeSet<T> {
map: BTreeMap<T, ()>,
}
what Rust type would use the least amount of memory
Any type with only one possible value uses zero bytes. () is an easy-to-type one.
See also:
What does an empty set of parentheses mean when used in a generic type declaration?

Is it possible to define tuples as members of structs in Rust?

I am very new to Rust and I was wondering if it's possible to define a tuple as a struct member. Something like:
struct MyStruct {
(x, y) : (u32, f32)
}
The compiler complains about the first comma, so this obviously isn't the right syntax. Is it even possible? I Can't find anything in the documentation, and if I search for tuple and struct I get results for tuple structs which is not what I'm looking for.
For anyone interested why I want to know this, I have a function that returns a tuple and I want to store the result inside a member of a struct. Currently I am calling the function on two temporary variables and then moving the results into two different struct members, but not sure if this is the right way to do it.
A tuple is a single variable which contains 2 values so when you define it in your struct it is still a single variable/field:
struct MyStruct {
x: (u32, f32),
}

Avoiding "cannot move out of borrowed content" without the use of "to_vec"?

I'm learning rust and have a simple program, shown below. Playground link.
#[derive(Debug)]
pub struct Foo {
bar: String,
}
pub fn gather_foos<'a>(data: &'a Vec<Vec<&'a Foo>>) -> Vec<Vec<&'a Foo>> {
let mut ret: Vec<Vec<&Foo>> = Vec::new();
for i in 0..data.len() {
if meets_requirements(&data[i]) {
ret.push(data[i].to_vec());
}
}
return ret
}
fn meets_requirements<'a>(_data: &'a Vec<&'a Foo>) -> bool {
true
}
fn main() {
let foo = Foo{
bar: String::from("bar"),
};
let v1 = vec![&foo, &foo, &foo];
let v2 = vec![&foo, &foo];
let data = vec![v1, v2];
println!("{:?}", gather_foos(&data));
}
The program simply loops through an array of arrays of a struct, checks if the array of structs meets some requirement and returns an array of arrays that meets said requirement.
I'm sure there's a more efficient way of doing this without the need to call to_vec(), which I had to implement in order to avoid the error cannot move out of borrowed content, but I'm not sure what that solution is.
I'm learning about Box<T> now and think it might provide a solution to my needs? Thanks for any help!!
The error is showing up because you're trying to move ownership of one of the vectors in the input vector to the output vector, which is not allowed since you've borrowed the input vector immutably. to_vec() creates a copy, which is why it works when you use it.
The solution depends on what you're trying to do. If you don't need the original input (you only want the matched ones), you can simply pass the input by value rather than by reference, which will allow you to consume the vector and move items to the output. Here's an example of this.
If you do need the original input, but you don't want to copy the vectors with to_vec(), you may want to use references in the output, as demonstrated by this example. Note that the function now returns a vector of references to vectors, rather than a vector of owned vectors.
For other cases, there are other options. If you need the data to be owned by multiple items for some reason, you could try Rc<T> or Arc<T> for reference-counted smart pointers, which can be cloned to provide immutable access to the same data by multiple owners.

Resources