I have a enum where I want to generalize an function pointer. As soon as I add a reference inside the function pointer definition. it fails to compile because it cannot print it with Debug:
fn div1(t: i64, b: i64) -> i64 {
t / b
}
fn div2(t: i64, b: &i64) -> i64 {
t / b
}
#[derive(Debug)]
enum Enum {
FnTest1(fn(i64, i64) -> i64),
FnTest2(fn(i64, &i64) -> i64),
}
fn main() {
println!("{:?}", Enum::FnTest1(div1));
println!("{:?}", Enum::FnTest2(div2));
}
The error I get is this
error[E0277]: `for<'r> fn(i64, &'r i64) -> i64` doesn't implement `std::fmt::Debug`
--> src/main.rs:12:13
|
12 | FnTest2(fn(i64, &i64) -> i64),
| ^^^^^^^^^^^^^^^^^^^^ `for<'r> fn(i64, &'r i64) -> i64` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
= help: the trait `std::fmt::Debug` is not implemented for `for<'r> fn(i64, &'r i64) -> i64`
= note: required because of the requirements on the impl of `std::fmt::Debug` for `&for<'r> fn(i64, &'r i64) -> i64`
= note: required for the cast to the object type `dyn std::fmt::Debug`
It only shows an error for FnTest2 which has a reference argument while FnTest1 works fine.
Is this a bug in Rust or is there a solution or an alternative method to this issue?
I am running Rust nightly (rustup says: rustc 1.30.0-nightly (ae7fe84e8 2018-09-26)).
Is this a bug in Rust
No, but it is a limitation:
Cannot derive(Debug) for a struct with a function with a reference parameter (#45048)
#[derive] Debug, PartialEq, Hash, etc. for any function pointers, regardless of type signature (#54508)
is there a solution or an alternative method
Yes, you must implement Debug for the type Enum yourself.
Related
I'm trying to create a trait with some default method implementation. One of the methods has to take an instance of the same type and perform some computations.
Here is the simplistic example of what I'm trying to achieve:
struct A {
val: f32,
}
trait S {
fn val(&self) -> f32;
fn add(&self, other: &Self) -> f32 {
add(&self, other)
}
}
impl S for A {
fn val(&self) -> f32 {
self.val
}
}
fn add<T: S>(first: &T, second: &T) -> f32 {
first.val() + second.val()
}
This fails to compile with the error:
15 | | fn add(&self, other: &Self) -> f32 {
16 | | add(&self, other)
| | ^^^^^ expected `&Self`, found type parameter `Self`
17 | | }
I do not understand the error message, for other is of type &Self not Self, so why does compiler thinks otherwise?
If I change it to reference add(&self, &other) (which doesn't seem right, since other is already a reference type), I get another error:
|
16 | add(&self, &other)
| ^^^ the trait `S` is not implemented for `&Self`
...
26 | fn add<T: S>(first: &T, second: &T) -> f32 {
| - required by this bound in `add`
Is there a way to achieve this with default trait implementation, or this can work only with concrete types (like in this question: How do I implement the Add trait for a reference to a struct?)?
EDIT: If I call it like add(self, other), it tries to send the trait object, but I want to send the objects by reference. And really, I want to send concrete implementations and not trait objects.
error[E0277]: the size for values of type `Self` cannot be known at compilation time
--> src/main.rs:16:9
|
16 | add(self, other)
| ^^^ doesn't have a size known at compile-time
You're passing &self to add(), which makes it a double reference and the arguments to add() don't agree in types. The T of add is apparently determined by the first argument, which is why the compiler appears to expect the other argument to also have the &&Self parameter. (Read the note at the end of the error message.)
Call it with add(self, other) and it will compile. Note that you'll also need to opt out of the implicit Sized bound on add by adding + ?Sized.
// rest as in your code
trait S {
fn val(&self) -> f32;
fn add(&self, other: &Self) -> f32 {
add(self, other)
}
}
fn add<T: S + ?Sized>(first: &T, second: &T) -> f32 {
first.val() + second.val()
}
Playground
This is a simpler version of my code:
type Res = Result<(), Box<dyn std::error::Error + Send + Sync>>;
// defined before-hand
pub trait Attr {
fn method(&self) -> Res;
}
// a struct, a block of code provided by user
// which is unknown by far
pub struct S;
// the trait implemented for provided struct
// user does this manually
// which is unknown by far
impl Attr for S {
fn method(&self) -> Res {
Ok(())
}
}
// in order to use the struct and its implemented method
// a possible way may be cast struct type to dynamic trait object
type Item = dyn Fn(&dyn Attr) -> Res;
pub fn use_method(f: &Item) {}
fn main() {
// casting happens here
// and do this job in macro, here is simplified version
let m = &(<S as Attr>::method) as &Item;
use_method(m);
}
It is required to tackle a struct, a block of code and its implementation both of which are unknown and provided by user. A rough direction may be using a trait as dynamic trait bounds which converted from struct object, but the compiler complain:
error[E0631]: type mismatch in function arguments
--> src/main.rs:30:13
|
4 | fn method(&self) -> Res;
| ------------------------ found signature of `for<'r> fn(&'r S) -> _`
...
30 | let m = &(<S as Attr>::method) as &Item;
| ^^^^^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r (dyn Attr + 'r)) -> _`
|
= note: required for the cast to the object type `dyn for<'r> Fn(&'r (dyn Attr + 'r)) -> std::result::Result<(), Box<(dyn std::error::Error + Send + Sync + 'static)>>`
How can I get it done? Is there any other way?
I'm trying to understand the implementation of Bevy's IntoForEachSystem trait and the way it interacts with the underlying Hecs Query and Fetch traits. Hecs has query types (the thing you request in a call to query::<T>) and item types (the thing returned by the query). The idea is that IntoForEachSystem is implemented for closures whose query type matches the query's item type, and fn f(&i32) works because an &i32 query returns an &i32 item.
I think I extracted the relevant parts of the design in this snippet, but I can't make it type check:
// Hecs Query trait
trait Query {
type Fetch: for<'a> Fetch<'a>;
}
// Hecs Query trait implementation for read-only references
impl<'a, T> Query for &'a T
where
T: 'static,
{
type Fetch = FetchRead<T>;
}
// Hecs Fetch trait
trait Fetch<'a>: Sized {
type Item;
}
// Hecs Fetch trait implementation for read-only references
struct FetchRead<T>(std::marker::PhantomData<T>);
impl<'a, T> Fetch<'a> for FetchRead<T>
where
T: 'static,
{
type Item = &'a T;
}
// Bevy IntoForEachSystem trait, simplified
trait IntoForEachSystem<R> {
fn system(self);
}
// Bevy IntoForEachSystem trait implementation for functions of one argument
impl<F, R> IntoForEachSystem<R> for F
where
F: Fn(R),
F: Fn(<<R as Query>::Fetch as Fetch>::Item),
R: Query,
{
fn system(self) {
println!("hello");
}
}
fn hmm(_x: &i32) {
todo!()
}
fn main() {
IntoForEachSystem::system(hmm)
}
Errors:
error[E0631]: type mismatch in function arguments
|
31 | fn system(self);
| ---------------- required by `IntoForEachSystem::system`
...
46 | fn hmm(_x: &i32) {
| ---------------- found signature of `for<'r> fn(&'r i32) -> _`
...
51 | IntoForEachSystem::system(hmm)
| ^^^ expected signature of `for<'r> fn(<FetchRead<i32> as Fetch<'r>>::Item) -> _`
|
= note: required because of the requirements on the impl of `IntoForEachSystem<&i32>` for `for<'r> fn(&'r i32) {hmm}`
I think the compiler is seeing the inferred lifetime 'r in fn hmm<'r>(&'r i32) as being different from the forall lifetime 'a in type Fetch: for<'a> Fetch<'a>. I don't see the trick that Bevy is using to achieve the same thing.
You're actually super close!
fn main() {
hmm.system();
}
This is ... very frustrating because IntoForEachSystem::system(hmm) should be equivalent to hmm.system() as far as I'm concerned. Maybe it's a bug in the Rust compiler?
I have a struct with a lifetime and some methods:
struct Ctrl<'a> {
x: &'a i32,
}
impl<'a> Ctrl<'a> {
fn foo(&self) -> i32 {
*self.x + 1
}
fn bar(&self) -> i32 {
*self.x + 2
}
}
Now I want to store pointers to the methods in a slice, kind of like a look-up table:
const LIST: &[_] = &[Ctrl::foo, Ctrl::bar];
Rust demands to know the slice element type and suggests for<'r> fn(&'r Ctrl) -> i32, but this results in an error:
error[E0308]: mismatched types
--> main.rs:16:48
|
16 | const LIST: &[for<'r> fn(&'r Ctrl) -> i32] = &[Ctrl::foo, Ctrl::bar];
| ^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'s, 'r> fn(&'r Ctrl<'s>) -> _`
found fn pointer `for<'r> fn(&'r Ctrl<'_>) -> _`
Is there a way to specify the correct type?
The problem is that foo is a method of Ctrl<'x> for some specific lifetime 'x, and not a method generic over all Ctrl<'_>. If you try to make all the lifetimes explicit, you will find that some of them can't be expressed:
const LIST: &[for<'a, 'b> fn(&'b Ctrl<'a>) -> i32] = &[Ctrl::<'?>::foo, Ctrl::<'?>::bar)];
// What lifetimes? ^^^^ ^^^^
Since foo isn't generic, but is bound to a specific Ctrl<'_>, there's no way to express the concept you need. You might try something like <for<'a> Ctrl<'a>>::foo, but that's not legal in current Rust.
One way to fix this would be to wrap each method in a closure that can be coerced to a function pointer:
const LIST: &[fn(&Ctrl<'_>) -> i32] = &[|this| this.foo(), |this| this.bar()];
This might get a little verbose if you have a lot of methods or if the signatures are more complex. Another option is to wrap each method in a free function with the correct signature. You could write a declarative macro to make it easier:
/// Wrap `Ctrl::$method` in a free function and return it.
macro_rules! ctrl {
($method:ident) => {{
fn inner(this: &Ctrl<'_>) -> i32 {
this.$method()
}
inner
}};
}
const LIST: &[fn(&Ctrl<'_>) -> i32] = &[ctrl!(foo), ctrl!(bar)];
This question already has an answer here:
Sized is not implemented for the type Fn
(1 answer)
Closed 3 years ago.
After reading about trait aliases, I tried to switch this code:
pub fn authorize<LoadClient>(get_client: LoadClient) -> Result<String, ()>
where
LoadClient: FnOnce(String) -> Result<Client, LoadingError>,
{
unimplemented!()
}
to
#![feature(trait_alias)]
trait LoadClient = FnOnce(String) -> Result<Client, ClientLoadingError>;
pub fn authorize(get_client: LoadClient) -> Result<String, ()> {
unimplemented!()
}
This gives me an error:
warning: trait objects without an explicit `dyn` are deprecated
--> src/oauth2/mod.rs:396:21
|
396 | get_client: LoadClient,
| ^^^^^^^^^^ help: use `dyn`: `dyn LoadClient`
|
= note: `#[warn(bare_trait_objects)]` on by default
error[E0277]: the size for values of type `(dyn std::ops::FnOnce(std::string::String) -> std::result::Result<oauth2::Client, oauth2::ClientLoadingError> + 'static)` cannot be known at compilation time
--> src/oauth2/mod.rs:396:9
|
396 | get_client: LoadClient,
| ^^^^^^^^^^ doesn't have a size known at compile-time
|
Is it possible to use a trait alias in this way? This function is used elsewhere so it would be nice to have a shared definition rather than redefine it at each place it's used.
This is related to Can match on Result here be replaced with map_err and "?"
You still need to use it as generic parameter:
#![feature(trait_alias)]
pub trait LoadClient = FnOnce(String) -> Result<Client, ClientLoadingError>;
pub fn authorize<T>(get_client: T) -> Result<String, ()>
where
T: LoadClient,
{
unimplemented!()
}
You also need to make the trait alias public since it is part of a public interface.
It seems this was just a naive mistake related to using traits as arguments, rather than anything specific to trait aliases. I need to use impl LoadClient as described in the rust book when using traits as function parameters.
With the signature
pub fn authorize(get_client: impl LoadClient) -> Result<String, ()>
the code compiles.