Multiply all elements in a generic vector? [duplicate] - rust

This question already has answers here:
How to write a trait bound for adding two references of a generic type?
(1 answer)
How does "for<>" syntax differ from a regular lifetime bound?
(1 answer)
Closed 2 years ago.
I'm trying to multiply all elements in a vector but I can't figure out how to do this with a reference. Here is an example:
struct S<T> {
elements: Vec<T>,
}
impl<T> std::ops::MulAssign<T> for S<T>
where
T: std::ops::MulAssign,
{
fn mul_assign(&mut self, val: T) {
for i in 0..self.elements.len() {
self.elements[i] *= val;
}
}
}
This doesn't compile:
error[E0382]: use of moved value: `val`
--> src/lib.rs:11:33
|
9 | fn mul_assign(&mut self, val: T) {
| --- move occurs because `val` has type `T`, which does not implement the `Copy` trait
10 | for i in 0..self.elements.len() {
11 | self.elements[i] *= val;
| ^^^ value moved here, in previous iteration of loop
I've tried this with references in different ways, but I didn't succeed. How do you do this? I would prefer to implement this without the Copy trait.

Maybe like this?
struct S<T> {
elements: Vec<T>,
}
impl<T> std::ops::MulAssign<&T> for S<T>
where
for<'a> T: std::ops::MulAssign<&'a T>,
{
fn mul_assign(&mut self, val: &T) {
for i in self.elements.iter_mut() {
*i *= val;
}
}
}
Uses iter_mut to iterate over vector
Requires that your elements support multiplication by borrowed T (which seems to be the case for isize and others

Extra notes:
I wouldn't recommend direct index assignment such as elements[i]. You can achieve the same with a for element in self.elements. Rust iterators will directly understand you want to iterate over the whole vec, so you can apply the processing on the element object.
A direct index access will add bound-checking at runtime, making it a slower solution, instead of safely iterating over the array with the length pre-calculated.
Furthermore, if you want to apply the same processing over the vec, the .map() method can help greatly, taking a closure to defiune the processing you want. Rust offers many such functional higher-order-functions, that are much more concise and efficient.

Related

impl Trait for primitives and references of [duplicate]

This question already has answers here:
What are Rust's exact auto-dereferencing rules?
(4 answers)
Closed 9 months ago.
Perhaps it is a simple question, but I can't understand why just impl'ing Trait for the primitive, owned type, I got for free the same impl for reference types...
trait Cool: Sized + std::fmt::Debug {
fn cool(self) {
println!("cool -> {:?}", self);
}
}
impl Cool for i32 {}
// it still works if this line is uncommented...
// impl Cool for &i32 {}
fn main(){
let val = 123;
val.cool();
(&val).cool();
}
Playground
It is not just because of primitives, it will work for all types that implement Copy. Will not work otherwise:
trait Cool: Sized + std::fmt::Debug {
fn cool(self) {
println!("cool -> {:?}", self);
}
}
#[derive(Debug)]
struct NonCopy;
impl Cool for i32 {}
impl Cool for NonCopy {}
fn main(){
let val = 123;
val.cool();
(&val).cool();
let nc = NonCopy{};
nc.cool();
(&nc).cool();
}
Fails with a clear error code:
error[E0507]: cannot move out of a shared reference
--> src/main.rs:20:5
|
20 | (&nc).cool();
| ^^^^^^------
| | |
| | value moved due to this method call
| move occurs because value has type `NonCopy`, which does not implement the `Copy` trait
|
Playground
What it's happening is that with the Copy types rust creates a copy transparently for you when needed.
Note that it fails even if we comment out the previous line // nc.cool();, which obviously moves the value...
That's auto-dereferencing; it applies whenever you use the . operator. It's meant to erase the distinction between . and -> which exists in C and related languages.
It was introduced in RFC 241.

Lifetimes when returning a reference to the contents of Rc<RefCell<_>> [duplicate]

This question already has answers here:
How do I return a reference to something inside a RefCell without breaking encapsulation?
(3 answers)
How do I borrow a RefCell<HashMap>, find a key, and return a reference to the result? [duplicate]
(1 answer)
Closed 2 years ago.
How can I return a reference to something from inside a shared pointer (in this case Rc<RefCell<_>>)? In the example below, I show how it can be done with just a regular mutable reference to self, but if it becomes a shared pointer instead, the compiler gets angry that the return type has a missing lifetime specifier.
error[E0106]: missing lifetime specifier
--> src/main.rs:19:60
|
19 | fn add_to_shared(me: Rc<RefCell<Thing>>, item: i32) -> &i32 {
| ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
help: consider using the `'static` lifetime
|
19 | fn add_to_shared(me: Rc<RefCell<Thing>>, item: i32) -> &'static i32 {
| ^^^^^^^^
use std::cell::RefCell;
use std::rc::Rc;
struct Thing {
items: Vec<i32>,
}
impl Thing {
fn new() -> Self {
Thing { items: Vec::new() }
}
fn add_to_self(&mut self, item: i32) -> &i32 {
self.items.push(item);
self.items.last().unwrap()
}
// does not compile
fn add_to_shared(me: Rc<RefCell<Thing>>, item: i32) -> &i32 {
me.borrow().items.push(item);
me.borrow().items.last().unwrap()
}
}
fn main() {
let mut thing = Thing::new();
println!("{}", thing.add_to_self(10));
let mut rc = Rc::new(RefCell::new(Thing::new()));
println!("{}", rc.add_to_shared(20));
}
Why do I want to do this? I have a program that builds a tree-like structure with multiple ownership. One of the associated methods takes two nodes of the tree (each shared pointers) and bundles them together into another part of the tree. Each method returns a reference to the newly created node so that it can be conveniently logged out (see the example).
I was thinking I'd need to use lifetime annotations to get this to work, but I have not been able to find out how do apply this concept to the interior of a Rc<RefCell<_>> type.
I think the problem here is that Rust knows how long self lives, but is not able to figure out how long Rc<RefCell<_>> exists. Do you need to return i32 references? If you would return just i32, the value would be copied and you would not have a reference into a struct that might not exists long enough.

How do I return an iterator over the keys of a HashSet from a trait method? [duplicate]

This question already has answers here:
What is the correct way to return an Iterator (or any other trait)?
(2 answers)
Is it possible to use `impl Trait` as a function's return type in a trait definition?
(4 answers)
"Expected type parameter" error in the constructor of a generic struct
(1 answer)
Closed 3 years ago.
A struct has a set of items I'd like to allow clients to iterate over. Here's an attempt:
use std::collections::HashSet;
use std::hash::Hash;
pub struct Foo<T: Eq + Hash> {
items: HashSet<T>,
}
impl<'a, T: 'a + Eq + Hash> Foo<T> {
pub fn new() -> Self {
Foo {
items: HashSet::new(),
}
}
pub fn iterate<I>(&self) -> I
where
I: IntoIterator<Item = &'a T>,
{
self.items.iter()
}
}
This fails to compile, giving the error:
error[E0308]: mismatched types
--> src/lib.rs:19:9
|
15 | pub fn iterate<I>(&self) -> I
| - expected `I` because of return type
...
19 | self.items.iter()
| ^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::collections::hash_set::Iter`
|
= note: expected type `I`
found type `std::collections::hash_set::Iter<'_, T>`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
The return value from HashSet::iter method appears to act like an Iterator when, for example within a for loop. It seems like some kind of type coercion might be possible in my iterate method, but clearly the compiler has other ideas.
How can I specify a return type of Iterator in a function while returning the return value from a HashSet iterator?
In other words, I want to delegate iteration to HashSet. I'd like to avoid implementing a custom iterator to do this, but if that's the only way would be interested in seeing how it's done. I've been able to get this working by returning a Box<dyn Iterator>, but I'd like to avoid that approach as well if it's possible to work just with trait boundaries as described in this answer.
One more requirement: the approach must work when the iterate method is declared on a trait. That appears to rule out an approach like:
pub trait FooTrait {
fn iterate(&self) -> impl Iterator<Item=&T>;
}
You want impl Iterator:
impl<'a, T: 'a + Eq + Hash> Foo<T> {
// ...
pub fn iterate(&'a self) -> impl Iterator<Item = &'a T> {
self.items.iter()
}
}
The Rust book has this section covering it. It is defined and refined in RFC 1522, RFC 1951, and RFC 2071. It isn't all done yet and has this tracking issue.

Can I transfer ownership of local variables and references to them to a returned iterator? [duplicate]

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)
How can I store a Chars iterator in the same struct as the String it is iterating on?
(2 answers)
Is there an owned version of String::chars?
(6 answers)
Closed 4 years ago.
I am using a trait with a method that returns an boxed iterator. Since the iterator will use self and the parameters of foo, all are constrained to the same lifetime:
pub trait Foo {
fn foo<'a>(&'a self, txt: &'a str) -> Box<Iterator<Item = String> + 'a>;
}
I would like to build a function around this method:
fn foo_int<'a, F: Foo>(f: &'a F, val: i32) -> impl Iterator<Item = String> + 'a {
let txt = format!("{}", val);
f.foo(&txt)
}
But that does not compile, because:
error[E0515]: cannot return value referencing local variable `txt`
--> src/lib.rs:7:5
|
7 | f.foo(&txt)
| ^^^^^^----^
| | |
| | `txt` is borrowed here
| returns a value referencing data owned by the current function
I understand why this happens, and it makes sense, but it seems to be that there should be a way to get around it. After all, that's what closures (with the move keyword) do: they take ownership of the values they need to "take away with them".
Is there a clever way to rewrite the foo_int function, using a closure or something else?
Actually, while working my minimal example, I came up with an idea that (kind of) solves the problem. It is available in the playground.
The idea is to wrap the parameter of foo and the returned iterator in a dedicated type, which itself implements the Iterator trait by delegating to the inner iterator.
pub struct Bar<'a>(String, Box<Iterator<Item = String> + 'a>);
impl<'a> Bar<'a> {
fn new<F: Foo>(foo: &'a F, txt: String) -> Bar<'a> {
let itr = foo.foo(unsafe { &*(&txt[..] as *const str) });
Bar(txt, itr)
}
}
impl<'a> Iterator for Bar<'a> {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.1.next()
}
}
fn foo_int<'a, F: Foo>(f: &'a F, val: i32) -> impl Iterator<Item = String> + 'a {
Bar::new(f, format!("{}", val))
}
I'm not entirely satisfied with that solution, though, because of the following reasons.
It is rather specific to this particular method; for another method with other parameters, I would need a different wrapper type.
It uses unsafe code. I believe this one is ok (because the inner &str of String is stable through move), but it might be harder (if not impossible) to achieve with other types.
It forces me to re-implement Iterator. While this minimal version works, it is suboptimal because the underlying iterator may have optimized implementations of some methods, which I "loose" here by relying on the default implementations. Implementing all methods of Iterator by hand (to pass them through to self.1) is tedious, and brittle (if further versions add new methods, I would have to add them as well).
So any better solution is still welcome...
edit: #Shepmaster's arguments convinced me; this is actually the same old problem of storing a value and a reference to it. So it is unsafe, and my solution is not general, because in general, it may not work :-/

Packaging common function arguments into struct - reducing repetition, fighting borrow checker [duplicate]

This question already has answers here:
Mutably borrow one struct field while borrowing another in a closure
(2 answers)
Closed 5 years ago.
This snippet
use std::collections::HashMap;
struct Foo {
local_ids: HashMap<i32, i32>,
last_id: i32,
}
impl Foo {
fn foo(&mut self, external_id: i32) {
let id = self.local_ids
.entry(external_id)
.or_insert_with(||{self.last_id += 1; self.last_id});
}
}
Doesn't work because we can't borrow self twice
error: closure requires unique access to `self` but `self.local_ids` is already borrowed [E0500]
Is this possible to fix without a second key lookup?
This is very similar to Rust: HashMap borrow issue when trying to implement find or insert, but the API has changed substantially.
The find_with_or_insert_with answer from above doesn't appear to map to the current api.
The problem is that the closure captures self, whereas it only needs to capture a mutable reference to the last_id field.
Rust allows us to take independent mutable borrows on distinct fields, so we can use that to our advantage and pass a mutable reference to the last_id field to the closure.
use std::collections::HashMap;
struct Foo {
local_ids: HashMap<i32, i32>,
last_id: i32,
}
impl Foo {
fn foo(&mut self, external_id: i32) {
let last_id = &mut self.last_id;
let id = self.local_ids
.entry(external_id)
.or_insert_with(|| { *last_id += 1; *last_id });
}
}
When we use the expression self.last_id in the closure, the closure captures self directly, but Rust doesn't realize that the borrows are independent, so we need to be more explicit.

Resources