Produce Option<Vec<String>> out of an Option<Vec<Custom>> in Rust - rust

I'm trying to do the equivalent of Ruby's Enumerable.collect() in Rust.
I have an Option<Vec<Attachment>> and I want to create a Option<Vec<String>> from it, with String::new() elements in case of None guid.
#[derive(Debug)]
pub struct Attachment {
pub guid: Option<String>,
}
fn main() {
let ov: Option<Vec<Attachment>> =
Some(vec![Attachment { guid: Some("rere34r34r34r34".to_string()) },
Attachment { guid: Some("5345345534rtyr5345".to_string()) }]);
let foo: Option<Vec<String>> = match ov {
Some(x) => {
x.iter()
.map(|&attachment| attachment.guid.unwrap_or(String::new()))
.collect()
}
None => None,
};
}
The error in the compiler is clear:
error[E0277]: the trait bound `std::option::Option<std::vec::Vec<std::string::String>>: std::iter::FromIterator<std::string::String>` is not satisfied
--> src/main.rs:15:18
|
15 | .collect()
| ^^^^^^^ the trait `std::iter::FromIterator<std::string::String>` is not implemented for `std::option::Option<std::vec::Vec<std::string::String>>`
|
= note: a collection of type `std::option::Option<std::vec::Vec<std::string::String>>` cannot be built from an iterator over elements of type `std::string::String`
If I remember what I've read from the documentation so far, I cannot implement traits for struct that I don't own.
How can I do this using iter().map(...).collect() or maybe another way?

You should read and memorize all of the methods on Option (and Result). These are used so pervasively in Rust that knowing what is present will help you immensely.
For example, your match statement is Option::map.
Since you never said you couldn't transfer ownership of the Strings, I'd just do that. This will avoid any extra allocation:
let foo: Option<Vec<_>> =
ov.map(|i| i.into_iter().map(|a| a.guid.unwrap_or_else(String::new)).collect());
Note we don't have to specify the type inside the Vec; it can be inferred.
You can of course introduce functions to make it cleaner:
impl Attachment {
fn into_guid(self) -> String {
self.guid.unwrap_or_else(String::new)
}
}
// ...
let foo: Option<Vec<_>> = ov.map(|i| i.into_iter().map(Attachment::into_guid).collect());
If you don't want to give up ownership of the String, you can do the same concept but with a string slice:
impl Attachment {
fn guid(&self) -> &str {
self.guid.as_ref().map_or("", String::as_str)
}
}
// ...
let foo: Option<Vec<_>> = ov.as_ref().map(|i| i.iter().map(|a| a.guid().to_owned()).collect());
Here, we have to use Option::as_ref to avoid moving the guid out of the Attachment, then convert to a &str with String::as_str, providing a default value. We likewise don't take ownership of the Option of ov, and thus need to iterate over references, and ultimately allocate new Strings with ToOwned.

Here is a solution that works:
#[derive(Debug)]
pub struct Attachment {
pub guid: Option<String>,
}
fn main() {
let ov: Option<Vec<Attachment>> =
Some(vec![Attachment { guid: Some("rere34r34r34r34".to_string()) },
Attachment { guid: Some("5345345534rtyr5345".to_string()) }]);
let foo: Option<Vec<_>> = ov.map(|x|
x.iter().map(|a| a.guid.as_ref().unwrap_or(&String::new()).clone()).collect());
println!("{:?}", foo);
}
One of the issues with the above code is stopping the guid being moved out of the Attachment and into the vector. My example calls clone to move cloned instances into the vector.
This works, but I think it looks nicer wrapped in a trait impl for Option<T>. Perhaps this is a better ... option ...:
trait CloneOr<T, U>
where U: Into<T>,
T: Clone
{
fn clone_or(&self, other: U) -> T;
}
impl<T, U> CloneOr<T, U> for Option<T>
where U: Into<T>,
T: Clone
{
fn clone_or(&self, other: U) -> T {
self.as_ref().unwrap_or(&other.into()).clone()
}
}
#[derive(Debug)]
pub struct Attachment {
pub guid: Option<String>,
}
fn main() {
let ov: Option<Vec<Attachment>> =
Some(vec![Attachment { guid: Some("rere34r34r34r34".to_string()) },
Attachment { guid: Some("5345345534rtyr5345".to_string()) },
Attachment { guid: None }]);
let foo: Option<Vec<_>> =
ov.map(|x| x.iter().map(|a| a.guid.clone_or("")).collect());
println!("{:?}", foo);
}
Essentially the unwrapping and cloning is hidden behind a trait implementation that attaches to Option<T>.
Here it is running on the playground.

Related

How can I mutate fields of a struct while referencing other fields?

Here's an example of a problem I ran into:
pub struct Item {
name: String,
value: LockableValue, // another struct that I'd like to mutate
}
impl Item {
pub fn name(&self) -> &str {
&self.name
}
pub fn value_mut(&mut self) -> &mut LockableValue {
&self.value
}
}
pub fn update(item: &mut Item) {
let value = item.value_mut();
value.change(); // how it changes is unimportant
println!("Updated item: {}", item.name());
}
Now, I know why this fails. I have a mutable reference to item through the mutable reference to the value.
If I convert the reference to an owned String, it works fine, but looks strange to me:
pub fn update(item: &mut Item) {
let name = { item.name().to_owned() };
let value = item.value_mut();
value.change(); // how it changes is unimportant
println!("Updated item: {}", name); // It works!
}
If I let value reference drop, then everything is fine.
pub fn update(item: &mut Item) {
{
let value = item.value_mut();
value.change(); // how it changes is unimportant
}
println!("Updated item: {}", item.name()); // It works!
}
The value.change() block is rather large, and accessing other fields in item might be helpful. So while I do have solutions to this issue, I'm wondering if there is a better (code-smell) way to do this. Any suggestions?
My intention behind the above structs was to allow Items to change values, but the name should be immutable. LockableValue is an tool to interface with another memory system, and copying/cloning the struct is not a good idea, as the memory is managed there. (I implement Drop on LockableValue to clean up.)
I was hoping it would be straight-forward to protect members of the struct from modification (even if it were immutable) like this... and I can, but it ends up looking weird to me. Maybe I just need to get used to it?
You could use interior mutability on only the part that you want to mutate by using a RefCell like ths:
use std::cell::{RefCell, RefMut};
pub struct LockableValue;
impl LockableValue {
fn change(&mut self) {}
}
pub struct Item {
name: String,
value: RefCell<LockableValue>, // another struct that I'd like to mutate
}
impl Item {
pub fn name(&self) -> &str {
&self.name
}
pub fn value_mut(&self) -> RefMut<'_, LockableValue> {
self.value.borrow_mut()
}
}
pub fn update(item: &Item) {
let name = item.name();
let mut value = item.value_mut();
value.change(); // how it changes is unimportant
println!("Updated item: {}", name);
}
That way you only need a shared reference to Item and you don't run into an issue with the borrow checker.
Not that this forces the borrow checks on value to be done at runtime though and thus comes with a performance hit.

How do i resolve type annotations needed cannot infer type for type parameter `T` ? What type annotation is needed to compile this code?

The blockchain struct definition, It defines a type and i use the type
pub struct Blockchain<T = SledDb> {
pub storage: T,
pub chain: Vec<Block>,
pub tip: Arc<RwLock<String>>,
pub height: AtomicUsize,
pub mempool: Mempool,
pub wallet: Wallet,
pub accounts: Account,
pub stakes: Stake,
pub validators: Validator,
}
This code is checking if stake is valid.The code for mining a block, the error is immited by is_staking_valid function. I don't know what type its asking for since i already specified one.
impl<T: Storage> Blockchain<T> {
pub fn is_staking_valid(
balance: u64,
difficulty: u32,
timestamp: i64,
prev_hash: &String,
address: &String,
) -> bool {
let base = BigUint::new(vec![2]);
let balance_diff_mul = base.pow(256) * balance as u32;
let balance_diff = balance_diff_mul / difficulty as u64;
let data_str = format!("{}{}{}", prev_hash, address, timestamp.to_string());
let sha256_hash = digest(data_str);
let staking_hash = BigUint::parse_bytes(&sha256_hash.as_bytes(), 16).expect("msg");
staking_hash <= balance_diff
}
pub fn mine_block(&mut self, data: &str) -> Option<Block> {
if self.mempool.transactions.len() < 2 {
info!("Skipping mining because no transaction in mempool");
return None;
}
let balance = self
.stakes
.get_balance(&self.wallet.get_public_key())
.clone();
let difficulty = self.get_difficulty();
info!("New block mining initialized with difficulty {}", difficulty);
let timestamp = Utc::now().timestamp();
let prev_hash = self.chain.last().unwrap().hash.clone();
let address = self.wallet.get_public_key();
if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
let block = self.create_block(&data, timestamp);
self.storage.update_blocks(&prev_hash, &block, self.height.load(Ordering::Relaxed));
Some(block)
} else {
None
}
}
}
Please find the compiler error below
error[E0282]: type annotations needed
--> src/blocks/chain.rs:173:12
|
173 | if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
For more information about this error, try `rustc --explain E0282`.
Minimized example:
pub struct Blockchain<T> {
pub storage: T,
}
impl<T> Blockchain<T> {
pub fn is_staking_valid() {
todo!()
}
pub fn mine_block(&mut self) {
Blockchain::is_staking_valid();
}
}
Playground
The reason for this error is that Blockchain::<T1>::is_staking_valid and Blockchain::<T2>::is_staking_valid are, as well as compiler is concerned, two separate, entirely unrelated functions. Yes, they have the same code, and yes, they will be deduplicated by the optimizer, but this doesn't have to be the case - e.g., if this function used some associated item available on T:
trait Stakable {
const IS_VALID: bool;
}
impl Stakable for () {
const IS_VALID: bool = false;
}
impl Stakable for i32 {
const IS_VALID: bool = true;
}
struct Blockchain<T> {
pub _storage: T,
}
impl<T: Stakable> Blockchain<T> {
fn validate() {
if !T::IS_VALID {
panic!("Type is not valid");
}
}
}
fn main() {
// This panics - we catch this panic and show that it has indeed happened
std::panic::catch_unwind(|| Blockchain::<()>::validate()).unwrap_err();
// This executes successfully
Blockchain::<i32>::validate();
}
Playground
Because of the possible ambiguity, compiler refuses to choose by itself and forces you to make the selection explicitly.
So, you have several possible ways to go:
Make is_staking_valid a free function, instead of associated function of Blockchain. In this case, it won't be able to depend on Blockchain's type parameter, therefore the call will be unambiguous.
Call Self::is_staking_valid instead of Blockchain::is_staking_valid. In this case, Self will be replaced with Blockchain::<T>, with T taken from the currently executed method; this will, again, resolve ambiguity.
Make is_staking_valid a method on Blockchain, i.e. make it receive &self, and call it via self.is_staking_valid().
Not recommended, but still possible, - make is_staking_valid an associated function on Blockchain<T> for some specific T, e.g.:
pub struct Blockchain<T> {
pub storage: T,
}
impl Blockchain<()> {
// Note - no free type parameters here!
pub fn is_staking_valid() {
todo!()
}
}
impl<T> Blockchain<T> {
pub fn mine_block(&mut self) {
// Here, `Blockchain` is `Blockchain::<()>` - the method is set
Blockchain::is_staking_valid();
}
}

How can I denote a field that can be either Rc<T> or Weak<T>

I'd like to have a field in struct like this:
struct Foo<T> {
bar: Smart<T>
}
where bar could be either Rc<T or Weak<T>, depending on the "ownership relationships" between different instances of Foo. Is there any idiomatic way in Rust how to do this, other than to create a custom enum?
Is there any idiomatic way in Rust how to do this, other than to create a custom enum?
Just like most other "either this or that" choices in Rust, an enum is the idiomatic way.
An Peter's answer suggested, there is is no such abstraction in the stdlib. You can define a small enum to handle both cases:
use std::rc::{Rc, Weak};
enum MaybeStrong<T> {
Strong(Rc<T>),
Weak(Weak<T>),
}
impl<T> MaybeStrong<T> {
fn get(&self) -> Option<Rc<T>> {
match self {
MaybeStrong::Strong(t) => Some(Rc::clone(t)),
MaybeStrong::Weak(w) => w.upgrade(),
}
}
}
struct Foo<T> {
bar: MaybeStrong<T>
}
impl<T> Foo<T> {
fn from_weak(inner: Weak<T>) -> Self {
Self { bar: MaybeStrong::Weak(inner) }
}
fn from_strong(inner: Rc<T>) -> Self {
Self { bar: MaybeStrong::Strong(inner) }
}
fn say(&self) where T: std::fmt::Debug {
println!("{:?}", self.bar.get())
}
}
fn main() {
let inner = Rc::new("foo!");
Foo::from_weak(Rc::downgrade(&inner)).say();
Foo::from_strong(inner).say();
}
self.bar() will always return a Some if it was created from a strong pointer and return None in case it's a Weak and it's dangling. Notice that due to the fact that get() needs to create an owned Rc first, the method can't return a &T (including Option<&T>) because that &T could be dangling. This also means that all users of bar() will own one strong count on the inner value while processing, making it safe to use in any case.
This kind of construct is often called "Either" and there's a crate that looks like it can address some of the usual use-cases: https://docs.rs/either/1.5.3/either/
Then you could write
struct Foo<T> {
bar: Either<Weak<T>, Rc<T>>
}
Then an example function to get an Option<Rc<T>> might be:
impl <T> Foo<T> {
fn get_rc(self) -> Option<Rc<T>> {
self.bar
.map_left( |weak| weak.upgrade() )
.map_right( |v| Some(v) )
.into_inner()
}
}
Then it can be used like this:
fn main() {
let x = Rc::new(1);
let f_direct = Foo{ bar:Either::Right(x.clone()) };
println!("f_direct.get_rc() = {:?}", f_direct.get_rc());
let f_weak = Foo{ bar:Either::Left(Rc::downgrade(&x)) };
println!("f_weak.get_rc() = {:?}", f_weak.get_rc());
}
Link to complete example in the playground:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c20faaa46277550e16a3d3b24f3d1750

Why must the associated type be specified in a collection of trait object references?

Here is an offending example (Playground):
// Some traits
trait Behaviour {
type Sub: SubBehaviour;
}
trait SubBehaviour {}
// Some implementations of these traits
struct A;
impl Behaviour for A {
type Sub = B;
}
struct B;
impl SubBehaviour for B {}
// Struct that holds a collection of these traits.
struct Example<'a> {
behaviours: Vec<&'a dyn Behaviour>,
}
impl<'a> Example<'a> {
fn add_behaviour<T: Behaviour>(&mut self, b: &'a T) {
self.behaviours.push(b);
}
}
fn main() {
let b = A;
let mut e = Example {
behaviours: Vec::new(),
};
e.add_behaviour(&b);
}
I get:
error[E0191]: the value of the associated type `Sub` (from trait `Behaviour`) must be specified
--> src/main.rs:17:29
|
3 | type Sub: SubBehaviour;
| ----------------------- `Sub` defined here
...
17 | behaviours: Vec<&'a dyn Behaviour>,
| ^^^^^^^^^ help: specify the associated type: `Behaviour<Sub = Type>`
Why must this type must be specified, particularly in this case where we are only storing a reference to the object? How can I get this code to work?
All types must be statically known at compile time. If Rust would allow different associated types for elements of a Vec, type information could depend on indices which are only known at runtime.
I find it helpful to consider a smaller example:
trait Behaviour {
type T;
fn make_t(&self) -> T;
}
fn foo(my_vec: Vec<&dyn Behaviour>, index: usize) {
let t = my_vec[index].make_t(); //Type of t depends on index
}
You were on the right track to fixing this though. I assume you introduced the SubBehaviour trait because you realized you need to put restrictions of what T can be. The thing is, in that case you don't need an associated type anymore.
trait SubBehaviour {}
trait Behaviour {
fn make_t(&self) -> Box<dyn SubBehaviour>;
fn ref_t(&self) -> &dyn SubBehaviour; // also fine
}
fn some_function(my_vec: Vec<&dyn Behaviour>, index: usize) {
let t1 = my_vec[index].make_t();
}
The only limitation is that in your definition of Behaviour you can not do anything which would depend on the size of T, (like allocating it on the stack or moving it) since the size of T can not be specified by the SubBehaviour trait.
You need to specify the associated type of the trait (i.e. Behavior<Sub = ???>).
When adding the associated type at all places, it compiles:
struct Example<'a, S: SubBehaviour + 'a> {
behaviours: Vec<&'a Behaviour<Sub = S>>,
}
impl<'a, S: SubBehaviour> Example<'a, S> {
fn add_behaviour<T: Behaviour<Sub = S>>(&mut self, b: &'a T) {
self.behaviours.push(b);
}
}
See this in action on the Playground
So the answer to your first question is covered by Tim's answer and is correct, you might not want your Example to be generic. In that case, you need to use some sort of type erasure:
// Some traits
trait Behaviour {
type Sub: SubBehaviour;
}
trait SubBehaviour {}
// Some implementations of these traits
struct A;
impl Behaviour for A {
type Sub = B;
}
struct B;
impl SubBehaviour for B {}
struct AnyBehaviour {
closure: Box<Fn()>,
}
impl AnyBehaviour {
fn new<U: SubBehaviour, T: Behaviour<Sub = U>>(b: &T) -> Self {
let closure = || {
//let sub = T::Sub::new();
println!("Can use T here");
};
AnyBehaviour {
closure: Box::new(closure),
}
}
}
// Struct that holds a collection of these traits.
struct Example {
behaviours: Vec<AnyBehaviour>,
}
impl Example {
fn add_behaviour<U: SubBehaviour, T: Behaviour<Sub = U>>(&mut self, b: &T) {
self.behaviours.push(AnyBehaviour::new(b));
}
}
fn main() {
let b = A;
let mut e = Example {
behaviours: Vec::new(),
};
e.add_behaviour(&b);
}
Within the closure, you have access to all the types needed call the traits functions with whatever subtype needed.
Why this happens, is mostly because you actually need a definition of the associated type in order for the trait to be "complete" so the compiler can work with it. Tim's answer answers that by the definition to be higher up in the chain (outside of Example) instead of inside.

How do I 'force' structs to implement the same traits?

I have the following:
pub struct OpBStruct {
title: String,
output_vale: i32,
}
impl OpBStruct {
pub fn new_OpB(in_title: String, in_output_vale: i32) -> OpBStruct {
OpBStruct {
title: in_title,
output_vale: in_output_vale,
}
}
}
pub struct OpCStruct {
title: String,
another_value: String,
output_vale: i32,
}
impl OpCStruct {
pub fn new_OpC(in_title: String, in_another_value: String, in_output_vale: i32) -> OpCStruct {
OpCStruct {
title: in_title,
another_value: in_another_value,
output_vale: in_output_vale,
}
}
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
pub enum Op {
OpB(OpBStruct),
OpC(OpCStruct),
}
pub struct A {
name: String,
operator: Op,
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
The exact structure of OpBStruct and OpCStruct are arbitrary and could be anything.
How do I make sure OpBStruct and OpCStruct implement a certain trait?
trait OpTrait {
pub fn get_op_output(&self) -> i32;
}
I thought about making a sort of constructor function that checked for an OpTrait trait requirement and it would be the only way one could create an Op instance, but each operator requires different initialization parameters and there's no way to specify a variable number of inputs for a function in Rust.
Something like this doesn't work because there's no way to input the initialization parameters:
pub fn new_op<T: OpTrait>(operator: T) {
// --snip--
}
I thought about somehow using the new_A method implemented on A to check if the in_operator has implemented the trait, but I'm not sure how to do that either.
What is the correct pattern for this? If there is none, I can just implement the trait for each Op with no sort of interface around it.
I would also recommend writing a test, however you can write a function which is generic over a type but takes no arguments:
struct X {}
trait Y {
fn yo();
}
fn is_y<T: Y>(){}
Then you can add the following line to do the check
is_y::<X>();
which will compile only if X implements Y.
Using a unit test would be a fairly straightforward way to enforce that you want a given trait on a struct. You can do it via implicit test code, but a small utility function to do so can express the intent a little more clearly.
If you have indicated trait inputs on functions in the rest of the code, it might come out fairly naturally without the unit test. The test has the advantage of letting you have an opportunity to explicitly check some invariant of the trait implementation too.
struct A {
val: u8,
}
struct B {
val: u32,
}
trait ExpandToU64 {
fn to_u64(&self) -> u64;
}
impl ExpandToU64 for A {
fn to_u64(&self) -> u64
{
self.val as u64
}
}
fn trait_tester<E>(a: E)
where E: ExpandToU64
{
// the utility function doesn't have to even use the trait...
// but you probably want to exercise the logic a bit
//let v = a.to_u64();
let v = 24u64;
println!("{:?}", v);
}
#[test]
fn test_needs_trait_ExpandToU64() {
let a = A { val:1 };
trait_tester(a);
let b = B { val:2 };
trait_tester(b);
// This fails with a compile error
// "the trait `ExpandToU64` is not implemented for `B`"
}

Resources