How to call a closure with AsRef<T> type?

I have a construct that looks like this:

struct Manager {
    the_fn: Box<dyn Fn(u32)>
}

impl Manager {
    pub fn new<T: 'static>(user_fn: impl Fn(u32, &T) + 'static, data: T) -> Self {
        Self {
            the_fn: Box::new(move |param| {
                user_fn(param, &data)
            })
        }
    }
}

Can be used like:

fn test() {
    Manager::new(my_func, String::from("users.rust-lang.org"));
}

fn my_func(param: u32, data: &String) {
    /* ...  */
}

But I would like to allow for this signature:

fn my_func(param: u32, data: &str) {
    /* ...  */
}

So what I tried is this, by using the AsRef<T> trait:

struct Manager {
    the_fn: Box<dyn Fn(u32)>
}

impl Manager {
    pub fn new<R: 'static, T: AsRef<R> + 'static>(user_fn: impl Fn(u32, &R) + 'static, data: T) -> Self {
        Self {
            the_fn: Box::new(move |param| {
                user_fn(param, AsRef::as_ref(&data))
            })
        }
    }
}

However, I get error:

the size for values of type str cannot be known at compilation time
the trait Sized is not implemented for str

I understand that size of str cannot be known at compilation time.

But we only ever use it as a reference/borrow! :face_with_raised_eyebrow:

So, is there any way how this code could be fixed to work as intended?

...or do I need a completely different approach?

Thanks.

Try this:

- T: AsRef<R>
+ T: AsRef<R> + ?Sized

This gives a different error:

The size for values of type T cannot be known at compilation time
doesn't have a size known at compile-time

It should be R: ?Sized rather than T: ?Sized.

-    pub fn new<R: 'static, T: AsRef<R> + 'static>(user_fn: impl Fn(u32, &R) + 'static, data: T) -> Self {
+    pub fn new<R: ?Sized + 'static, T: AsRef<R> + 'static>(user_fn: impl Fn(u32, &R) + 'static, data: T) -> Self {

Playground

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.