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.
Related
I'm having a hard time finding any useful examples of how to use nom to parse a binary file, since it seems that the documentation is heavily biased towards &str input parsers.
I just want to make a function here that will read 4 bytes, turn it into a u32 and return it as a result. Here is my function:
fn take_u32(input: &[u8]) -> IResult<&[u8], u32> {
map_res(
take(4),
|bytes| Ok(u32::from_be_bytes(bytes))
)(input)
}
I'm getting the following error:
error[E0277]: the trait bound `[u8; 4]: From<u8>` is not satisfied
--> src\main.rs:16:9
|
16 | take(4),
| ^^^^ the trait `From<u8>` is not implemented for `[u8; 4]`
|
::: C:\Users\cmbas\.cargo\registry\src\github.com-1ecc6299db9ec823\nom-7.1.0\src\bits\complete.rs:39:6
|
39 | O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O>,
| -------- required by this bound in `nom::complete::take`
What is the canonical way to do what I'm attempting?
take() return Self aka your input, In your case slice &[u8].
map_res() is used to map a Result, from_be_bytes() doesn't return a result, the doc also contains an example using TryInto::try_into.
To make your code compile you need to use map_opt() and use try_into() to transform the slice to array:
fn take_u32(input: &[u8]) -> IResult<&[u8], u32> {
map_opt(
take(4),
|bytes| int_bytes.try_into().map(u32::from_be_bytes)
)(input)
}
That said nom already have such basic conbinator be_u32
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,
}
}
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
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.
Editor's note: This question was asked before Rust 1.0. Since then, many functions and types have changed, as have certain language semantics. The code in the question is no longer valid, but the ideas expressed in the answers may be.
I'm trying to list the files in a directory and copy the filename to my own Vec. I've tried several solutions, but it always ends up with a problem of not being able to create long enough living variables. I don't understand my mistake.
fn getList(action_dir_path : &str) -> Vec<&str> {
let v = fs::readdir(&Path::new(action_dir_path))
.unwrap()
.iter()
.map(|&x| x.filestem_str().unwrap())
.collect();
return v;
}
Why does the compiler complain about "x" ? I don't care about x, I want the &str inside it and I thought &str were static.
I tried this way, but I got the same result with the compiler complaining about "paths" not living long enough.
fn getList2(action_dir_path : &str) -> Vec<&str> {
let paths = fs::readdir(&Path::new(action_dir_path)).unwrap();
let mut v : Vec<&str> = Vec::new();
for path in paths.iter(){
let aSlice = path.filestem_str().unwrap();
v.push(aSlice);
}
return v;
}
Here is the playground.
The most literal translation of your code that supports Rust 1.0 is this:
use std::{fs, path::Path, ffi::OsStr};
fn getList(action_dir_path: &str) -> Vec<&OsStr> {
let v = fs::read_dir(&Path::new(action_dir_path))
.unwrap()
.map(|x| x.unwrap().path().file_stem().unwrap())
.collect();
return v;
}
This produces the error messages:
Rust 2015
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:6:18
|
6 | .map(|x| x.unwrap().path().file_stem().unwrap())
| ^^^^^^^^^^^^^^^^^ - temporary value only lives until here
| |
| temporary value does not live long enough
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 3:1...
--> src/lib.rs:3:1
|
3 | / fn getList(action_dir_path: &str) -> Vec<&OsStr> {
4 | | let v = fs::read_dir(&Path::new(action_dir_path))
5 | | .unwrap()
6 | | .map(|x| x.unwrap().path().file_stem().unwrap())
7 | | .collect();
8 | | return v;
9 | | }
| |_^
Rust 2018
error[E0515]: cannot return value referencing temporary value
--> src/lib.rs:6:18
|
6 | .map(|x| x.unwrap().path().file_stem().unwrap())
| -----------------^^^^^^^^^^^^^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| temporary value created here
The problem comes from Path::file_stem. This is the signature:
pub fn file_stem(&self) -> Option<&OsStr>
This indicates that the method will return a borrowed reference to a OsStr. The PathBuf struct is the owner of the string. When you leave the method, there's nowhere left that owns the PathBuf, so it will be dropped. This means that any references into the PathBuf will no longer be valid. This is Rust preventing you from having references to memory that is no longer allocated, yay for Rust!
The easiest thing you can do is return a Vec<String>. String owns the string inside of it, so we don't need to worry about it being freed when we leave the function:
fn get_list(action_dir_path: &str) -> Vec<String> {
fs::read_dir(action_dir_path)
.unwrap()
.map(|x| {
x.unwrap()
.path()
.file_stem()
.unwrap()
.to_str()
.unwrap()
.to_string()
})
.collect()
}
I also updated the style (at no charge!) to be more Rust-like:
Use snake_case for items
No space before the colon in type definitions
There's no reason to set a variable just to return it.
Don't use explicit return statements unless you are exiting from a function early.
There's no need to wrap the path in a Path.
However, I'm not a fan of all of the unwrapping. I'd write the function like this:
use std::{ffi::OsString, fs, io, path::Path};
fn get_list(action_dir_path: impl AsRef<Path>) -> io::Result<Vec<OsString>> {
fs::read_dir(action_dir_path)?
.map(|entry| entry.map(|e| e.file_name()))
.collect()
}
fn main() {
println!("{:?}", get_list("/etc"));
}
In addition to the changes above:
I use a generic type for the input path.
I return a Result to propagate errors to the caller.
I directly ask the DirEntry for the filename.
I leave the type as an OsString.
One small related point:
I thought &str were static.
&'static strs are static, but that's only one kind of &str. It can have any kind of lifetime.