Capturing a local variable in a local function [duplicate] - rust

This question already has answers here:
How can I implement Ord when the comparison depends on data not part of the compared items?
(2 answers)
Closed 2 years ago.
I have this maze-like thing with 2 points in it and I want the distance between those points through the maze. To do this I will use A* (unless there is a better algorithm I don't know about), but to use A* I need my SN (search node) struct to implement the Ord trait. I want to use the Manhattan distance from 1 location to another as heuristic, so I had code like this (playground):
use std::cmp::Ordering;
fn main() {
let something_i_need_in_cmp = 5;
struct SN {
loc: u16,
step: u16,
}
impl Ord for SN {
fn cmp(&self, other: &Self) -> Ordering {
let tc = self.step + something_i_need_in_cmp;
let oc = other.step + something_i_need_in_cmp;
tc.cmp(&oc)
}
}
}
This does not work because the to variable is not captured:
error[E0434]: can't capture dynamic environment in a fn item
--> src/main.rs:13:34
|
13 | let tc = self.step + something_i_need_in_cmp;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use the `|| { ... }` closure form instead
error[E0434]: can't capture dynamic environment in a fn item
--> src/main.rs:14:35
|
14 | let oc = other.step + something_i_need_in_cmp;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use the `|| { ... }` closure form instead
error[E0277]: can't compare `SN` with `SN`
--> src/main.rs:11:10
|
11 | impl Ord for SN {
| ^^^ no implementation for `SN < SN` and `SN > SN`
|
= help: the trait `PartialOrd` is not implemented for `SN`
error[E0277]: the trait bound `SN: Eq` is not satisfied
--> src/main.rs:11:10
|
11 | impl Ord for SN {
| ^^^ the trait `Eq` is not implemented for `SN`
Is there any way around this?
The error hints use the `|| { ... }` closure form instead, but I don't seem to be able to get this right. Can this help fix it?
An answer I found online suggested to add the extra data (the to variable in my case) to the struct (here SN but for searching like this that would mean that the to variable (or a reference to it) is copied a 100 times, which is not efficient.

It looks to me like you're wanting to use a dynamic ordering for the points, but the big problem here is that Ord (and all other Rust traits) need to be defined statically, at compile-time.
My suggestion is that instead of using bare SN structs in your code, use SN structs 'decorated' with a distance, i.e. (u32, SN). These tuples derive Ord so they ought to work in your priority queues, etc.
You still need an impl Ord for SN implementation for the (Distance, SN) trick to work. The good news here is that any arbitrary Ord definition, including a default one (#[derive(...)]) will work.
use std::cmp::Ordering;
fn main() {
let something_i_need_in_cmp = 5;
#[derive(Eq, PartialEq, Ord, PartialOrd)]
struct SN {
loc: u16,
step: u16,
}
}

Related

Rust adding associated type with u32

I have an associated type MyType.
This type is going to be an unsigned integer, but I use it because the size of the unsigned integer required for this variable is maybe going to change in the future. So MyType is going to be one of: u32, u64, u128.
So MyType will look like this when defined: MyType = u32 (of course it may not be u32).
In my code, I need to increment this variable of type MyType by one.
so I have to do this: let n: MyType = v + 1, where v is the type of MyType.
How can I do this, what trait restrictions should MyType have?
I would want something like this: type MyType: UnsignedInt, but the problem is there is no number trait in rust as far as I have seen.
Your description is very vague and it would be much easier if you added a code example, but deriving from the word associated type I tried to reconstruct a minimal example:
trait Incrementor {
type MyType;
fn increment(&self, value: Self::MyType) -> Self::MyType {
value + 1
}
}
struct U32Incrementor;
impl Incrementor for U32Incrementor {
type MyType = u32;
}
fn main() {
let incrementor = U32Incrementor;
println!("{}", incrementor.increment(10));
}
error[E0369]: cannot add `{integer}` to `<Self as Incrementor>::MyType`
--> src/main.rs:5:15
|
5 | value + 1
| ----- ^ - {integer}
| |
| <Self as Incrementor>::MyType
|
= note: the trait `std::ops::Add` is not implemented for `<Self as Incrementor>::MyType`
Is that about the problem you are having?
If yes, does this help?
use num_traits::{FromPrimitive, One, Unsigned};
trait Incrementor {
type MyType: Unsigned + FromPrimitive;
fn increment(&self, value: Self::MyType) -> Self::MyType {
value + Self::MyType::one()
}
fn increment_ten(&self, value: Self::MyType) -> Self::MyType {
value + Self::MyType::from_u8(10).unwrap()
}
}
struct U32Incrementor;
impl Incrementor for U32Incrementor {
type MyType = u32;
}
fn main() {
let incrementor = U32Incrementor;
println!("{}", incrementor.increment(10));
println!("{}", incrementor.increment_ten(10));
}
11
20
It's based on the excellent num_traits crate.
The + operator behavior is specified by the trait std::ops::Add. This trait is generic over its output type, so if you want for example MyType to have the semantics MyType + MyType = MyType you can write:
trait MyTrait {
type MyType: std::ops::Add<Output = Self::MyType>;
}
All integers will implement this. If you need additional operators you can use the traits from std::ops, but with multiple bounds this can become tedious. The crate num-traits can help you with pre-declared traits that has all required ops and more. For example the trait NumOps specify all arithmetic operators, and there are more traits such as Num that includes equality and zero/one or PrimInt that specifies basically every operation or method integers in Rust have.

Is it possible to check equality of closures in rust?

I am pretty new to rust, but for a practice project I am working on, I would like to implement a React useMemo like API, and I thought if the type of the closure is static, and the capture variables are stored somewhere, should I not be able to check equality?
Something like:
let cached = scope.use_memo(move || {
complicated_computation(captured_variable)
});
where use_memo is something like
pub fn use_memo<F: Fn() -> T + PartialEq + 'static, T: Clone + 'static>(&mut self, factory: F) -> &T
where in the code I can compare factory with a previously stored factory function and decide if factory needs to be rerun.
Obviously this doesn't work, since closures don't implement PartialEq, but I wonder if there are ways to achieve it.
No. Every closure has a separate type, even if they're identical, and you can't compare cross-type.
Looking at a minimal example:
fn main() {
let b = 2;
let a = if true {
|| println!("{}", b)
} else {
|| println!("{}", b)
};
}
we get a compiler error that helpfully explains that no two closures, even if identical, have the same type.
Compiling playground v0.0.1 (/playground)
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:6:9
|
3 | let a = if true {
| _____________-
4 | | || println!("{}", b)
| | -------------------- expected because of this
5 | | } else {
6 | | || println!("{}", b)
| | ^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
7 | | };
| |_____- `if` and `else` have incompatible types
|
= note: expected type `[closure#src/main.rs:4:9: 4:29 b:_]`
found closure `[closure#src/main.rs:6:9: 6:29 b:_]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
error: aborting due to previous error
You could build structs that contain the environment explicitly and compare those rather than using a closure, but I would suggest rethinking your problem and seeing if this is the best way to solve it.
I don't think it's possible: Rust closures are somewhat anonymous type so you can't implement traits on them or anything. And if you used more "explicit" closures where you build up the environment by hand and pass a simple function pointers:
fn use_memo<T: PartialEq>(&mut self, env: T, func: fn(T))
you could compare them:
fn main(){
let a: fn(u8) -> u8 = |a: u8| a;
let b: fn(u8) -> u8 = |a: u8| a % 2;
println!("{}", a == b) -> false
}
but then you'd have the issue that different callbacks would have different environments, therefore the types would not match and you still would not be able to compare them, probably.
I am also quite new in rust, but an idea might be to have a custom trait FactoryIdentifiable that defines a method get_identifier.
You could then use operator overloading and implement PartialEq for this trait and modify your closure's type signature to also require this trait.
pub fn use_memo<F: Fn() -> T + FactoryIdentifiable, T: Clone + 'static>(&mut self, factory: F) -> &T

What is the correct way to get values via a method without moving it? [duplicate]

This question already has answers here:
How to prevent a value from being moved?
(2 answers)
When would an implementation want to take ownership of self in Rust?
(2 answers)
What do I have to do to solve a "use of moved value" error?
(3 answers)
How can I solve "use of moved value" and "which does not implement the `Copy` trait"?
(1 answer)
Closed 3 years ago.
I don't understand why Rust moves the value. Do I oversee a major point in the ownership?
The struct MyData is a smaller version. I store some values in this struct, and want to access the stored values, but the compiler tells me after the second access, that the value was moved.
I want to make some getters for my structs. I already derived Clone, but that does not help.
The problem occurs on Windows 10 with the GNU-Compiler and on Kubuntu 18.04 LTS.
My current workaround is to clone the data beforehand, but this can't be the correct way.
#[derive(Debug, Clone)]
struct MyData {
val1: i32,
val2: String,
}
impl MyData {
pub fn get_val1(self) -> i32 {
return self.val1.clone();
}
pub fn get_val2(self) -> String {
return self.val2.clone();
}
pub fn get_both(self) -> (i32, String) {
return (self.val1, self.val2);
}
}
fn main() {
let d = MyData {
val1: 35,
val2: String::from("Hello World"),
};
let both = d.get_both();
let x = d.get_val1();
let y = d.get_val2();
}
error[E0382]: use of moved value: `d`
--> src/main.rs:28:13
|
27 | let both = d.get_both();
| - value moved here
28 | let x = d.get_val1();
| ^ value used here after move
|
= note: move occurs because `d` has type `MyData`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `d`
--> src/main.rs:29:13
|
28 | let x = d.get_val1();
| - value moved here
29 | let y = d.get_val2();
| ^ value used here after move
|
= note: move occurs because `d` has type `MyData`, which does not implement the `Copy` trait
I expect that let x = d.get_val1(); won't cause an error. In my understanding of ownership in Rust, I did not move the value, since I'm calling a method of MyData and want to work with the value.
Why does Rust move the value and to whom?

How can I implement a trait using existing function implementations? [duplicate]

This program dies because of infinite recursion:
use std::any::Any;
trait Foo {
fn get(&self, index: usize) -> Option<&Any>;
}
impl Foo for Vec<i32> {
fn get(&self, index: usize) -> Option<&Any> {
Vec::get(self, index).map(|v| v as &Any)
}
}
fn main() {
let v: Vec<i32> = vec![1, 2, 4];
println!("Results: {:?}", v.get(0))
}
The compiler itself warns about this:
warning: function cannot return without recurring
--> src/main.rs:8:5
|
8 | fn get(&self, index: usize) -> Option<&Any> {
| _____^ starting here...
9 | | Vec::get(self, index).map(|v| v as &Any)
10 | | }
| |_____^ ...ending here
|
= note: #[warn(unconditional_recursion)] on by default
note: recursive call site
--> src/main.rs:9:9
|
9 | Vec::get(self, index).map(|v| v as &Any)
| ^^^^^^^^^^^^^^^^^^^^^
= help: a `loop` may express intention better if this is on purpose
Why does universal call syntax not work in this case? The compiler does not understand that I want to call Vec::get not Foo::get.
How can I fix this, if I do not want to change function names?
To specify which method to call, whether inherent or provided from a trait, you want to use the fully qualified syntax:
Type::function(maybe_self, needed_arguments, more_arguments)
Trait::function(maybe_self, needed_arguments, more_arguments)
Your case doesn't work because Vec doesn't have a method called get! get is provided from the Deref implementation to [T].
The easiest fix is to call as_slice directly:
self.as_slice().get(index).map(|v| v as &Any)
You could also use the fully qualified syntax which requires the angle brackets in this case (<...>) to avoid ambiguity with declaring an array literal:
<[i32]>::get(self, index).map(|v| v as &Any)
universal call syntax
Note that while Rust originally used the term universal function call syntax (UFCS), the usage of this term conflicted with the existing understood programming term, so the use of it is not suggested. The replacement term is fully qualified syntax.

How to call a method when a trait and struct use the same method name?

This program dies because of infinite recursion:
use std::any::Any;
trait Foo {
fn get(&self, index: usize) -> Option<&Any>;
}
impl Foo for Vec<i32> {
fn get(&self, index: usize) -> Option<&Any> {
Vec::get(self, index).map(|v| v as &Any)
}
}
fn main() {
let v: Vec<i32> = vec![1, 2, 4];
println!("Results: {:?}", v.get(0))
}
The compiler itself warns about this:
warning: function cannot return without recurring
--> src/main.rs:8:5
|
8 | fn get(&self, index: usize) -> Option<&Any> {
| _____^ starting here...
9 | | Vec::get(self, index).map(|v| v as &Any)
10 | | }
| |_____^ ...ending here
|
= note: #[warn(unconditional_recursion)] on by default
note: recursive call site
--> src/main.rs:9:9
|
9 | Vec::get(self, index).map(|v| v as &Any)
| ^^^^^^^^^^^^^^^^^^^^^
= help: a `loop` may express intention better if this is on purpose
Why does universal call syntax not work in this case? The compiler does not understand that I want to call Vec::get not Foo::get.
How can I fix this, if I do not want to change function names?
To specify which method to call, whether inherent or provided from a trait, you want to use the fully qualified syntax:
Type::function(maybe_self, needed_arguments, more_arguments)
Trait::function(maybe_self, needed_arguments, more_arguments)
Your case doesn't work because Vec doesn't have a method called get! get is provided from the Deref implementation to [T].
The easiest fix is to call as_slice directly:
self.as_slice().get(index).map(|v| v as &Any)
You could also use the fully qualified syntax which requires the angle brackets in this case (<...>) to avoid ambiguity with declaring an array literal:
<[i32]>::get(self, index).map(|v| v as &Any)
universal call syntax
Note that while Rust originally used the term universal function call syntax (UFCS), the usage of this term conflicted with the existing understood programming term, so the use of it is not suggested. The replacement term is fully qualified syntax.

Resources