Am I moving or cloning this String - rust

I have an enum defined like this:
#[derive(Clone, Debug)]
pub enum JsonState {
NameReadingState(String),
StringState(String),
}
impl JsonState {
pub fn get_name_read(self) -> String {
if let JsonState::NameReadingState(name) = self {
return name;
} else {
panic!(
"Error: attempted to get name from non name state {:#?}",
self
);
}
}
}
If I were to call get_name_read on an instance of JsonState would the string be moved out of the enum or would it be copied? My understanding is that since I am passing self and not &self I am taking ownership of the instance inside the function and so I should be able to simply move the string out of it.

It is moved.
This is, in my opinion, one of the great advantages of Rust over C++: if you don't see a .clone() anywhere, then you are not cloning! In Rust, there are no implicit deep copies like in C++. If you want to create a copy/clone then you have to do it explicitly by calling a method that clones your instance.
All of this comes with one exception: types that implement Copy. These types use copy semantics instead of move semantics. It should be noted that Copy can only be implemented for types "whose values can be duplicated simply by copying bits", i.e. very simple types. String and any other types that manage heap memory do not implement Copy.

Related

How to implement value-like semantics for non-trivial types in rust

I would like to write a type that has an implementation for the Drop trait. but I would like to not need to call .clone() every time I need a copy like a type that implement Copy. But from what I understood, I cannot use the Copy trait because it can only be implemented for trivial types that can be memcpyed around and is incompatible with the Drop trait.
for example:
use std::rc::Rc;
#[derive(Clone)]
struct Impl {
//... details
}
#[derive(Clone)]
struct ValueLikeHandle {
handle : Rc<Impl>
}
impl ValueLikeHandle {
pub fn new() -> ValueLikeHandle {
ValueLikeHandle { handle : Rc::new(Impl{}) }
}
}
fn main() {
let a = ValueLikeHandle::new();
let b = a; // I would like this to be a .clone() with out writing it.
let c = a;
}
How can I implement value semantics for a non-trivial type ?
To the best of my knowledge you can't. This is a conscious design decision to prevent gotchas.
Clone has the potential to be expensive and therefore shouldn't happen implicitly. Also, it would be a gotcha because assignment either uses move semantics for non-copy types and copy semantics for copy types, but never clones.
In some languages you could overload the assignment operator to implement clone semantics, but Rust doesn't allow that.

How to access item in nested hashmap without multiple clones?

There is a TokenBalances struct defined using a nested map. I want to implement a the balance_of method which takes two keys: token, account as input, and returns the balance as output.
use std::collections::*;
type TokenId = u128;
type AccountId = u128;
type AccountBalance = u128;
#[derive(Default, Clone)]
struct TokenBalances {
balances: HashMap<TokenId, HashMap<AccountId, AccountBalance>>,
}
impl TokenBalances {
fn balance_of(&self, token: TokenId, account: AccountId) -> AccountBalance {
self.balances
.get(&token)
.cloned()
.unwrap_or_default()
.get(&account)
.cloned()
.unwrap_or_default()
}
}
fn main() {
println!("{}", TokenBalances::default().balance_of(0, 0)) // 0
}
It uses cloned twice to turn an Option<&T> to Option<T>
I'm aware of to_owned as an alternative to cloned, but in its docs it says
Creates owned data from borrowed data, usually by cloning.
I'm wondering if the clones are really necessary. Is there any idomatic way to rewrite the method without cloning twice? And are clones completely avoidable?
You can use Option::and_then:
self.balances
.get(&token)
.and_then(|map| map.get(&account))
.copied()
.unwrap_or_default()
The and_then call returns an Option<&AccountBalance>. This is then cloned/copied with copied. This is fine as it's just a u128 right now. If it ever becomes a more complex type where copying isn't cheap, make balance_of return &AccountBalance instead. Then you can remove the copied() call and unwrap_or(&0) for example.
Last note: the unwrap_or_default might hint at a code smell. I don't know your context, but it might make more sense to actually return Option<AccountBalance> from the method instead of defaulting to 0.
Your need to clone comes from the fact that you are using unwrap_or_default inbetween. Without the clone, you have an Option<&HashMap> (as per HashMap::get on the outer map) and &HashMap does not implement Default - where should this default reference point to? Luckily, we don't actually need an owned HashMap, the reference to the inner map totally suffices to do a lookup. To chain two functions that may return None, one uses Option::and_then. It is like Option::map, but flattens an Option<Option<T>> into just an Option<T>. In your case, the code would look like this:
impl TokenBalances {
fn balance_of(&self, token: TokenId, account: AccountId) -> AccountBalance {
self.balances
.get(&token)
.and_then(|inner_map| inner_map.get(&account))
.copied()
.unwrap_or_default()
}
}
I also changed the final cloned to copied, which indicates that this clone is cheap.

Rust treat two different structs as one

I have two different structs with similar functions. Suppose that the program choose which struct to take from the user input.
I want to write something like this
fn main() {
...
let obj = if a == first {
first_object //struct First
} else {
second_object//struct Second
};
obj.read();
obj.write();
obj.some_another_method();
}
I have tried to make an enumeration
pub enum ObjectKind {
FirstObject(First),
SecondObject(Second)
}
But I cannot use methods in this case
let something = ObjectKind::FirstObject(first_object);
something.read()
//no method named `read` found for enum `structs::ObjectKind` in the current scope
//method not found in `structs::ObjectKind`
But I cannot use methods in this case
An enum is a proper type in and of itself, it's not a "union" of existing types. You can just define the methods on the enum to forward to the relevant object e.g.
impl ObjectKind {
fn read(&self) {
match self {
FirstObject(f) => f.read()
SecondObject(s) => s.read()
}
}
}
as it would probably be a bit repetitive, you can use a macro to make the forwarding easier.
Alternatively, you might be able to define a trait for the common behaviour and use a trait object to dynamically dispatch between the two, but that can be somewhat restrictive.

Is it possible to assign the return value of different functions that return different structs (that implement a common trait) to a single variable?

Let's say I have something like this:
trait SomeTrait {}
struct One;
impl SomeTrait for One {}
struct Two;
impl SomeTrait for Two {}
fn return_one() -> One {
One
}
fn return_two() -> Two {
Two
}
Somewhere else, I want to essentially do:
fn do_stuff(op: Operation) {
let result = match op {
Operation::OpOne => return_one(),
Operation::OpTwo => return_two(),
};
}
That of course doesn't compile, as those two return_*() functions return distinct types. I've tried:
Declaring result as dyn SomeTrait (still error: mismatched types)
Casting the return values, e.g. return_one() as dyn SomeTrait (error: cast to unsized type: One as dyn SomeTrait)
Making Sized a supertrait of SomeTrait (this won't work for me in this particular case as I don't have control over the real-world version of SomeTrait, but it doesn't compile anyway: error: the trait SomeTrait cannot be made into an object
Things I think would work but don't want to or can't do:
Boxing values on return, e.g. Box::new(return_one()) as dyn Box<SomeTrait> (having to move the values into a box, and thus off the stack, seems excessive)
Having return_one() and return_two() instead return impl SomeTrait (this would allow me to accidentally return Two from return_one(), for example, and I want to use the type system to prevent that)
Wrapping with an enum: I don't want the functions to return a wrapper enum, because then we have the same problem as the previous bullet point. I could wrap the return values in an enum at the call site, and that could work, but let's say there's some function on SomeTrait that I want to call at the end; it seems like a lot of extra boilerplate to then unwrap the enum and call that function for each inner type. If I were to do that, I might as well just copy-paste the trait function call to each match arm.
I found a few crates on crates.io that claim to be able to do this, but AFAICT they all require implementing a trait on the types, which are foreign types for me, so I can't do that.
Is it possible to make this work?
A possible option is to do the following
fn do_stuff(op: Operation) {
let (one, two);
let _result: &dyn SomeTrait = match op {
Operation::OpOne => {one = return_one(); &one},
Operation::OpTwo => {two = return_two(); &two},
};
}
You can also use &mut dyn SomeTrait instead if you need to borrow it mutably.
This is somewhat verbose, but if you find yourself doing it a lot, a macro
that declares the anonymous variables, assigns them and returns a reference might help.
Another solution could be to use the auto_enums crate, which automaticaly creates the enum and implements the trait for it, the downside is that it only supports certain traits, (mostly in std, I believe) and that for this specific use case it requires nightly, or putting the match in a separate function.
I'm not sure I can link a specific part of the docs, but if you scroll down to "#Rust Nightly", you'll see your specific use of it, something like as follows
use auto_enums::auto_enum;
fn do_stuff(op: Operation) {
#[auto_enum(SomeTrait)]
let _result = match op {
Operation::OpOne => return_one(),
Operation::OpTwo => return_two(),
};
}
Although keep in mind this only works if auto_enums supports SomeTrait.

How to offer an API that stores values of different types and can return them with the original type restored?

I want to offer a safe API like below FooManager. It should be able to store arbitrary user-defined values that implement a trait Foo. It should also be able to hand them back later - not as trait object (Box<dyn Foo>) but as the original type (Box<T> where T: Foo). At least conceptually it should be possible to offer this as a safe API, by using generic handles (Handle<T>), see below.
Additional criteria:
The solution should work in stable Rust (internal usage of unsafe blocks is perfectly okay though).
I don't want to modify the trait Foo, as e.g. suggested in How to get a reference to a concrete type from a trait object?. It should work without adding a method as_any(). Reasoning: Foo shouldn't have any knowledge about the fact that it might be stored in containers and be restored to the actual type.
trait Foo {}
struct Handle<T> {
// ...
}
struct FooManager {
// ...
}
impl FooManager {
// A real-world API would complain if the value is already stored.
pub fn keep_foo<T: Foo>(&mut self, foo: Box<T>) -> Handle<T> {
// ...
}
// In a real-world API this would return an `Option`.
pub fn return_foo<T: Foo>(&mut self, handle: Handle<T>) -> Box<T> {
// ...
}
}
I came up with this (Rust Playground) but not sure if there's a better way or if it's safe even. What do you think of that approach?

Resources