This question already has answers here:
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 1 year ago.
imagine you have this two structs, one for creating things and one to store them.
struct Things {
name: String,
}
struct Backpack<'backpack> {
all_things: Option<Vec<Things>>,
favorite: Option<[&'backpack Things; 2]>,
}
all_things in Backpack are all the things that you are carrying around, but you can choose only two to be your favorite things.
in orther to add things to your backpack you run this code
let thing1 = Things {
name: String::from("pencil"),
};
let thing2 = Things {
name: String::from("notebook"),
};
let thing3 = Things {
name: String::from("phone"),
};
let mut my_backpack = Backpack {
all_things: None,
favorite: None,
};
my_backpack.all_things = Some(vec![thing1, thing2, thing3]);
you first initialize your backpack to be empty, and then add some items to your backpack.
The problem I have is to add items to favorite, because I only want a reference to that item from all_things.
my_backpack.favorite = Some([
&my_backpack.all_things.unwrap()[0],
&my_backpack.all_things.unwrap()[1],
])
whenever I do this, I got a compile error saying that the value has being moved.
How can I create an array of my favorite things with only references from all_things that are in my backpack. I don't want to copy them because they already exists on all_things.
Note that all_things and favorite can be empty, so that's why I use Option enum.
When you do my_backpack.all_things.unwrap(), you take the ownership of the value in the Option enum, thus the borrow checker error.
All you need to do is to reference the vector instead of taking the ownership:
my_backpack.favorite = Some([
&my_backpack.all_things.as_ref().unwrap()[0],
&my_backpack.all_things.as_ref().unwrap()[1],
]);
Related
This is my data model:
pub struct RaffleDetails {
prize: Balance,
start: Timestamp,
end: Timestamp,
participants: UnorderedMap<AccountId, Balance>,
}
pub struct RaffleDapp {
raffles: UnorderedMap<AccountId, RaffleDetails>,
}
How can I insert a key-value pair in the 'participants' variable?
I tried self.raffles.get(&raffle_account_id).unwrap().participants.insert(&env::predecessor_account_id(), &confidence); but it's not persistent.
References:
UnorderedMap
NEAR Rust SDK
You need to make sure you are updating the RaffleDetails instance that is in the map, not a copy/clone of it.
I'm not familiar with UnorderedMap, but it seems to me the get() method returns a copy of the value that is in the map, so you are only updating the copied value. I don't know if UnorderedMap allows you to mutate a value in it directly (skimming through the docs, I don't see such a method). What you can do though is re-insert the modified RaffleDetails into the raffles map (so as to replace the old one with the modified one).
I'm talking about something like this (I haven't tested compiling it):
let o = self.raffles.get(&raffle_account_id);
if let copied_rd = Some(o) {
copied_rd.participants.insert(&env::predecessor_account_id(), &confidence);
self.raffles.insert(&raffle_account_id, &copied_rd);
}
I have found a way to move context into several closures, but it looks ugly. I do it with help of Rc and cloning each variable I need to use for each closure. Particularly I don't like to clone every variable for every closure I want to use:
let mut context = Rc::new( Context { a : 13 } );
..
let context_clone_1 = Rc::clone( &context );
engine.on_event1( Box::new( move ||
{
println!( "on_event1 : {}", context_clone_1.a );
...
let context_clone_2 = Rc::clone( &context );
engine.on_event2( Box::new( move ||
{
println!( "on_event1 : {}", context_clone_1.a );
...
It is an extensive way to go and I feel there must be a better way to do it. Also, uncommenting line // context_clone_1.a += 1; breaks the compilation. What is the proper way of solving problems like this in Rust?
Here is a playground with minimal code.
There are two "problems" here:
Since you specifically asked about context_clone_1.a += 1;: When putting a value into an Rc, there could be multiple references to that value, derived from the independent Rc owners. If mutation was allowed, this would also allow simultaneous mutation and aliasing, which is not allowed in Rust; therefore Rc does not allow mutating its inner value. A common approach to regain mutability is to put the value into a RefCell, which provides mutability through try_borrow_mut() with a runtime check that ensures no aliasing occurs. A Rc<RefCell<T>> is commonly seen in Rust.
Regarding the use of Rc: The way your code is currently set up is actually fine, at least if that's how it should work. The way the code is currently structured allows for flexibility, including cases where multiple Context-objects provide callback implementations on different events. For example, this is currently possible:
let context1 = Context { a : 13 };
engine.on_event1(Box::new(move ||
{
println!("on_event1 : {}", context1.a );
});
let context2 = Context { a : 999 };
engine.on_event2(Box::new(move ||
{
println!("on_event1 : {}", context2.a );
});
In case you have exactly one Context (as in your example), and since the Engine needs to make sure that all callbacks are alive while it itself is alive, you'll need to put each callback - which is structured as a completely separate thing - into a Rc. In your case, all Rc end up pointing to the same object; but they don't have to and this is what your code currently allows for.
A more simple solution would be to define a trait for Context, something along the lines of
trait EventDriver {
fn event1(&mut self, &Engine);
fn event2(&mut self, &Engine);
}
... and then have Context implement the trait. The Engine-struct then becomes generic over E: EventDriver and Context becomes the E in that. This solution only allows for exactly one instance of Context to provide event callbacks. But since Engine is the owner of that object, it can be sure that all callbacks are alive while it itself is alive and the whole Rc-thing goes away.
Recently I started to learn Rust and one of my main struggles is converting years of Object Oriented thinking into procedural code.
I'm trying to parse a XML that have tags that are processed by an specific handler that can deal with the data it gets from the children.
Further more I have some field members that are common between them and I would prefer not to have to write the same fields to all the handlers.
I tried my hand on it and my code came out like this:
use roxmltree::Node; // roxmltree = "0.14.0"
fn get_data_from(node: &Node) -> String {
let tag_name = get_node_name(node);
let tag_handler: dyn XMLTagHandler = match tag_name {
"name" => NameHandler::new(),
"phone" => PhoneHandler::new(),
_ => DefaultHandler::new()
}
if tag_handler.is_recursive() {
for child in node.children() {
let child_value = get_data_from(&child);
// do something with child value
}
}
let value: String = tag_handler.value()
value
}
// consider that handlers are on my project and can be adapted to my needs, and that XMLTagHandler is the trait that they share in common.
My main issues with this are:
This feels like a Object oriented approach to it;
is_recursive needs to be reimplemented to each struct because they traits cannot have field members, and I will have to add more fields later, which means more boilerplate for each new field;
I could use one type for a Handler and pass to it a function pointer, but this approach seems dirty. e.g.:=> Handler::new(my_other_params, phone_handler_func)
This feels like a Object oriented approach to it
Actually, I don't think so. This code is in clear violation of the Tell-Don't-Ask principle, which falls out from the central idea of object-oriented programming: the encapsulation of data and related behavior into objects. The objects (NameHandler, PhoneHandler, etc.) don't have enough knowledge about what they are to do things on their own, so get_data_from has to query them for information and decide what to do, rather than simply sending a message and letting the object figure out how to deal with it.
So let's start by moving the knowledge about what to do with each kind of tag into the handler itself:
trait XmlTagHandler {
fn foreach_child<F: FnMut(&Node)>(&self, node: &Node, callback: F);
}
impl XmlTagHandler for NameHandler {
fn foreach_child<F: FnMut(&Node)>(&self, _node: &Node, _callback: F) {
// "name" is not a recursive tag, so do nothing
}
}
impl XmlTagHandler for DefaultHandler {
fn foreach_child<F: FnMut(&Node)>(&self, node: &Node, callback: F) {
// all other tags may be recursive
for child in node.children() {
callback(child);
}
}
}
This way you call foreach_child on every kind of Handler, and let the handler itself decide whether the right action is to recurse or not. After all, that's why they have different types -- right?
To get rid of the dyn part, which is unnecessary, let's write a little generic helper function that uses XmlTagHandler to handle one specific kind of tag, and modify get_data_from so it just dispatches to the correct parameterized version of it. (I'll suppose that XmlTagHandler also has a new function so that you can create one generically.)
fn handle_tag<H: XmlTagHandler>(node: &Node) -> String {
let handler = H::new();
handler.foreach_child(node, |child| {
// do something with child value
});
handler.value()
}
fn get_data_from(node: &Node) -> String {
let tag_name = get_node_name(node);
match tag_name {
"name" => handle_tag::<NameHandler>(node),
"phone" => handle_tag::<PhoneHandler>(node),
_ => handle_tag::<DefaultHandler>(node),
}
}
If you don't like handle_tag::<SomeHandler>(node), also consider making handle_tag a provided method of XmlTagHandler, so you can instead write SomeHandler::handle(node).
Note that I have not really changed any of the data structures. Your presumption of an XmlTagHandler trait and various Handler implementors is a pretty normal way to organize code. However, in this case, it doesn't offer any real improvement over just writing three separate functions:
fn get_data_from(node: &Node) -> String {
let tag_name = get_node_name(node);
match tag_name {
"name" => get_name_from(node),
"phone" => get_phone_from(node),
_ => get_other_from(node),
}
}
In some languages, such as Java, all code has to be part of some class – so you can find yourself writing classes that don't exist for any other reason than to group related things together. In Rust you don't need to do this, so make sure that any added complication such as XmlTagHandler is actually pulling its weight.
is_recursive needs to be reimplemented to each struct because they traits cannot have field members, and I will have to add more fields later, which means more boilerplate for each new field
Without more information about the fields, it's impossible to really understand what problem you're facing here; however, in general, if there is a family of structs that have some data in common, you may want to make a generic struct instead of a trait. See the answers to How to reuse codes for Binary Search Tree, Red-Black Tree, and AVL Tree? for more suggestions.
I could use one type for a Handler and pass to it a function pointer, but this approach seems dirty
Elegance is sometimes a useful thing, but it is subjective. I would recommend closures rather than function pointers, but this suggestion doesn't seem "dirty" to me. Making closures and putting them in data structures is a very normal way to write Rust code. If you can elaborate on what you don't like about it, perhaps someone could point out ways to improve it.
I have started out learning Rust and is currently trying to write a small neural network as personal exercise. I want to define a struct for my forthcoming Layers/Clusters/Groups of nodes. My initial definition looks like this:
struct Layer {
name: String, // Human readable name
id: String, // UUID in the future
order: u8, // int for sorting
width: u8, // Number of nodes
input: [&'Self], // References to other Layers that feed input into this
}
The thing I am struggling with is the input field which should contain a list of references to other Layer-instances. I will know at compile time how many each Layer will have in the list so it wont have to me mutable. Is it possible to do this? I cant find a solution on the Google machine or in "the book".
Please advise.
Is it possible to do this? I cant find a solution on the Google machine or in "the book".
Possible yes, though I would not recommend it.
Let's start with the possible: &Self would be a "layer reference" with an unnamed lifetime, a lifetime name is for the form '<symbol>, so when you write &'Self you're specifying a reference of lifetime 'Self, but you're never specifying the type being refered to, which is why rustc complains about "expected type".
If you add a "proper" lifetime name, and parametrize the structure, it compiles fine:
struct Layer<'sublayers> {
name: String, // Human readable name
id: String, // UUID in the future
order: u8, // int for sorting
width: u8, // Number of nodes
input: [&'sublayers Self], // References to other Layers that feed input into this
}
However I would not recommend it as the last member being a slice means it's a DST which are difficult to work with at the best of time -- as the nomicon specifically notes "custom DSTs are a largely half-baked feature for now".
Since Rust doesn't yet have const generics proper you can't use an array you'd parameterize through layer either (e.g. Layer<const Size> and input: [&Self;Size], maybe one day), so you probably want something like a vector or a slice reference e.g.
struct Layer<'slice, 'sublayers: 'slice> {
name: String, // Human readable name
id: String, // UUID in the future
order: u8, // int for sorting
width: u8, // Number of nodes
input: &'slice [&'sublayers Self], // References to other Layers that feed input into this
}
I'm learning Rust (coming from Javascript), and in Rust I'm trying to create a component-based UI template. This is the minimum example I can reproduce in a Rust playground.
I have a Vector of Enums. I want to add components that will return a new set of vectors. The component returns a vector from a member function that is not a reference.
let _new_children = match new_view.unwrap() {
View::View(children) => children, // reference &Vec<View>
View::Render(ref component) => component.render(), // struct Vec<View>
};
let _new_children = match new_view.unwrap() {
View::View(children) => children,
View::Render(ref component) => &component.render(), // temporary value dropped while borrowed
};
How can I solve this problem? Do I need to rewrite the way functions check the difference between two vectors (itertools has a zip_longest method, which I also use).
In order to return a reference to a temporary you need to make the temporary live longer than the use of that reference.
In your code the temporary object is dropped as soon as the match branch ends, so a reference to it cannot escape the match.
There is a nice trick in Rust to extend the lifetime of a temporary. It consist in declaring the temporary name+ in the larger block where you want it to live, without initializing it. Then you assign-initialize it where the object temporary is actually created. Something like this:
let tmp_new;
let new_children = match new_view.unwrap() {
View::View(children) => children,
View::Render(ref component) => {
tmp_new = component.render();
&tmp_new }
};
Now new_children is of type &Vec<_> and it will live for the shorter of the two lifetimes of the match branches.
Note that unless you initialize the temporary in every branch of your match you cannot use tmp_new after it, because you will get:
use of possibly-uninitialized variable: tmp_new