This question already has an answer here:
Lifetimes in HashMap where key refers to value
(1 answer)
Closed 10 months ago.
I want to create a hash map from a vector of entities. I want the key to be a reference to a field in the corresponding value. This is something I have come up with.
struct Entity {
id: String,
patterns: Vec<Pattern>,
}
struct Package<'ent> {
entity_map: HashMap<&'ent String, Entity>,
}
impl<'ent> Package<'ent> {
fn from(entities: Vec<Entity>) -> Self {
let entity_map: HashMap<&String, Entity> =
entities.into_iter().map(|e| (&e.id, e)).collect();
Package { entity_map }
}
}
Of course, this isn't working. I am pretty new to Rust. Is there anything wrong with this approach? How can I achieve what I want? Any help will be appreciated.
In this case I think your best bet is to have the HashMap's keys and values both be references to elements in the original Vec, which should itself be passed by reference (as a slice, the more general version of &Vec) instead of by value.
use std::collections::HashMap;
struct Pattern;
struct Entity {
id: String,
patterns: Vec<Pattern>,
}
struct Package<'ent> {
// Now the values are references too
entity_map: HashMap<&'ent String, &'ent Entity>,
}
impl<'ent> Package<'ent> {
// Package<'ent> can be constructed from any slice that outlives it
fn from(entities: &'ent [Entity]) -> Self {
let entity_map = entities
.iter()
.map(|e| (&e.id, e))
.collect::<HashMap<_, _>>();
Package { entity_map }
}
}
As an aside, if you're implementing the function from(T), you probably want to do so as part of the implementation of the trait From<T> for your type.
If you can't store the vector for long enough to make the above solution work, then you can simply split Entity into its key and value components, which can then be used as owned values in the HashMap.
// Same Pattern and Entity as above
struct EntityValue {
patterns: Vec<Pattern>,
}
impl Package {
fn from(entities: Vec<Entity>) -> Self {
let entity_map = entities
.into_iter()
.map(|e| {
let Entity { id, patterns } = e;
(id, EntityValue { patterns })
})
.collect::<HashMap<_, _>>();
Package { entity_map }
}
}
Related
This question already has answers here:
How to restrict the construction of struct?
(2 answers)
Closed 5 months ago.
I want to give some business-rule guarantees about certain structs. For example, that an EmailAddress is a valid email, or that a DateRange has a from that lies before a from, and so on. So that when passing such a value around, it is guaranteed to adhere to all business rules for that struct.
struct InvalidEmailAddress;
struct EmailAddress {
value: String
}
impl EmailAddress {
fn new(value: String) -> Result<Self, InvalidEmailAddress> {
if value.contains("#") { // I know, this isn't any sort of validation. It's an example.
Ok(Self { value })
} else {
Err(InvalidEmailAddress)
}
}
}
Ignoring that now new() behaves unexpected (it probably would be better to use a build() method), this brings an issue: When someone builds an EmailAddress through the constructor, it is guaranteed to be "valid". But when someone constructs it as normal struct, it may not be.:
let guaranteed_valid = EmailAddress::new(String::from("hi#example.com")).unwrap();
let will_crash = EmailAddress::new(String::from("localhost")).unwrap()
let unknown_valid = EmailAddress { value: String::from("hi-at-example.com") }
I would like to prohibit any users of those structs from constructing them directly like in the last line.
Is that possible at all? Are there any more ways someone could construct an EmailAddress in an invalid way?
I'm OK with placing the structs in a module, and using public/private visibility if that is possible at all. But from what I can see, any code that wants to now enforce the EmailAddress type, say a send_report(to: EmailAddress) would have access to the struct and can build it directly. Or am I missing something crucial?
You need to place your struct in a module. That way any code outside of that module will only be able to access the public functionality. Since value is not public, direct construction will not be allowed:
mod email {
#[derive(Debug)]
pub struct InvalidEmailAddress;
pub struct EmailAddress {
value: String,
}
impl EmailAddress {
pub fn new(value: String) -> Result<Self, InvalidEmailAddress> {
if value.contains("#") {
// I know, this isn't any sort of validation. It's an example.
Ok(Self { value })
} else {
Err(InvalidEmailAddress)
}
}
}
}
use email::EmailAddress;
fn main() {
let e = EmailAddress::new("foo#bar".to_string()).unwrap(); // no error
//let e = EmailAddress { value: "invalid".to_string() }; // "field `value` of struct `EmailAddress` is private"
}
Playground
More details on visibility in the Book.
This question already has answers here:
Obtain a reference from a RefCell<Option<Rc<T>>> in Rust
(1 answer)
How do I borrow a RefCell<HashMap>, find a key, and return a reference to the result? [duplicate]
(1 answer)
How do I return a reference to something inside a RefCell without breaking encapsulation?
(3 answers)
Closed 12 months ago.
Assume following code
pub struct Universe {
components: Rc<RefCell<Vec<Component>>>,
active_component: Rc<RefCell<Option<usize>>>,
}
I would like to introduce a convenience method that returns a mutable reference to the active component, e.g.
fn get_active_component(&mut self) -> Option<&mut Component> {
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let i = *active_component_idx;
return self.components.borrow_mut().get_mut(i);
}
Option::None
}
which results in error
145 | return self.components.borrow_mut().get_mut(i);
| ----------------------------^^^^^^^^^^^
| |
| returns a reference to data owned by the current function
| temporary value created here
I do understand the error. The borrow_mut() creates a temporary variable which goes out of scope after the function returns. But I have absolutely no idea how you would realize such a method in rust apart from always inlining the code.
The standard way would be to mimic what RefCell does -- return a proxy struct wrapping the RefMut from .borrow_mut() and containing the vector index, implementing Deref and DerefMut.
pub struct ComponentHandle<'a> {
vecref: RefMut<'a, Vec<Component>>,
index: usize,
}
impl Deref for ComponentHandle<'_> {
type Target = Component;
fn deref(&self) -> &Component {
// SAFETY: We already verified the index is valid, RefCell won't
// dispense another mutable reference while we hold the RefMut, and we
// don't modify the vector's length, so we know this index is valid.
unsafe { self.vecref.get_unchecked(self.index) }
}
}
impl DerefMut for ComponentHandle<'_> {
fn deref_mut(&mut self) -> &mut Component {
// SAFETY: We already verified the index is valid, RefCell won't
// dispense another mutable reference while we hold the RefMut, and we
// don't modify the vector's length, so we know this index is valid.
unsafe { self.vecref.get_unchecked_mut(self.index) }
}
}
impl Universe {
fn get_active_component(&mut self) -> Option<ComponentHandle<'_>> {
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let vecref = self.components.borrow_mut();
let index = *active_component_idx;
if index < vecref.len() {
return Some(ComponentHandle { vecref, index });
}
}
None
}
}
Alternatively, this function could accept a closure to invoke, passing it the bare reference. This is simpler to code, though less idiomatic:
fn get_active_component<F>(&mut self, f: F)
where F: FnOnce(Option<&mut Component>)
{
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let i = *active_component_idx;
f(self.components.borrow_mut().get_mut(i));
} else {
f(None);
}
}
I have an enum with a String:
enum MyLovelyEnum {
Thing(String),
}
For tests, I would like to be able to pass in a &'static str to avoid MyLovelyEnum::Thing("abc".to_string) over and over.
I found that you can do this nicely with structs with a constructor:
// From: https://hermanradtke.com/2015/05/06/creating-a-rust-function-that-accepts-string-or-str.html
struct Person {
name: String,
}
impl Person {
fn new<S: Into<String>>(name: S) -> Person {
Person { name: name.into() }
}
}
fn main() {
let person = Person::new("Herman");
let person = Person::new("Herman".to_string());
}
I know I can use lifetimes or Cow as described in What's the best practice for str/String values in Rust enums? or I can make my own function.
Is there something close to the example in the blog post for enums? e.g.
// this is the kind of thing I am after but this specifically is not correct syntax
enum MyLovelyEnum {
Thing<S: Into<String>>(S)
}
You can create a generic enum:
enum MyLovelyEnum<S>
where
S: Into<String>,
{
Thing(S),
}
MyLovelyEnum::Thing("a");
MyLovelyEnum::Thing("b".to_string());
I likely wouldn't do that in my code, instead opting to create a constructor, much like the blog post you linked:
enum MyLovelyEnum {
Thing(String),
}
impl MyLovelyEnum {
fn thing(s: impl Into<String>) -> Self {
MyLovelyEnum::Thing(s.into())
}
}
MyLovelyEnum::thing("a");
MyLovelyEnum::thing("b".to_string());
I have abstracted my problem inside the following code:
struct List<'a> {
attr: &'a String
}
impl<'a> List<'a> {
fn new() -> List<'a> {
let my_attr = "Something";
List {
attr: &my_attr.to_string()
}
}
}
fn main() {
List::new();
}
It yields some notices and fails compiling claiming that the borrowed value (my_attr) doesn't live long enough.
It makes sense, so for instance the following does indeed compile:
struct List<'a> {
attr: &'a String
}
impl<'a> List<'a> {
fn new(my_attr: &'a String) -> List<'a> {
List {
attr: my_attr
}
}
}
fn main() {
let my_attr = "Something".to_string();
List::new(&my_attr);
}
However, I like the first form more, especially from an encapsulation stand point.
Is it possible to create and also assign a reference to a value from within the new method (as per the failing example)?
The issue here is that a &'a String is a borrowed value - that is, it is a reference to a value that is stored elsewhere. On your first example, that "elsewhere" is the new function stack, and on the second it's main's stack.
You don't get an error on the second case because main's lifetime is bigger than your List's lifetime - that is, the List will die before main finishes. That is not the case of your first scenario, where the List is returned by new, and thus the reference is invalid.
The solution here is to make List own its String, instead of just taking a reference to it. This way, List's lifetime isn't linked to anything else.
struct List {
attr: String,
}
impl List {
fn new() -> List {
let my_attr = "Something";
List {
attr: my_attr.to_string()
}
}
}
I have the following code (as a cut-down example):
class Item {
attributes: ~mut [~str];
}
class ItemList {
items: ~mut [ ~Item ];
}
fn read_item(rdr : Reader) -> ~mut Item {
}
fn load_item_list(rdr : Reader) -> ~mut ItemList {
}
When trying to implement these functions, I keep running into errors like "unresolved name ItemList" and conflicts between pointer/mutability types (&~mut vs ~mut, etc.)
Could someone give me a cut-down example which just allocates and returns the empty objects? From there I should be able to fill in the data.
I'm not sure what problem you are hitting but here are a few pointers. First of all, I recommend moving to Rust trunk - the class syntax you are using indicates a fairly old version of Rust. On trunk, mut is no longer a valid modifier for the interior of owned types, meaning ~mut T cannot be written, nor struct { mut field: T }. Instead mutability of owned types is inherited through its root in the stack. So if you have type Foo = ~[~str], that type is deeply immutable when declared in let foo = ~[~"bar"] and deeply mutable when let mut foo = ~[~"bar"].
Here's an example based on your types.
struct Item {
attributes: ~[~str]
}
struct ItemList {
items: ~[ ~Item ]
}
fn read_item() -> ~Item {
~Item {
attributes: ~[~"puppies"]
}
}
fn load_item_list() -> ~ItemList {
~ItemList {
items: ~[read_item()]
}
}
fn main() {
let mut my_items = load_item_list();
my_items.items[0].attributes[0] = ~"kitties";
}
You can see that the types don't mention mutability at all, but because we load them into a mutable slot (let mut my_items), the values in the inner vector can be mutated.
This can take some time to get used to, but Rust deals with interior mutability this way to avoid some potentially confounding errors related to borrowed pointers.
The exception to this inherited mutability is with managed types, which can also be the root of mutability, as in #mut T.