"de-sugar" the map() return type

Hi all,
Can someone help me to desugar the return type of the .map() i.e. write down the exact in place of ... in the following code? Thank you.

let names_str = vec![   "AAA", "BBB", "CCC", "DDD"];

let map_len: `...` = names_str.iter().map( |name: &&str| name.len() );

it's Map<slice::Iter<'_, &str>, anonymous_closure_type>.

Closures don't have a type that can be spelled out syntactically. If you need that, you must coerce the closure to a concrete nameable type such as dyn FnMut(...) -> _ or fn(...) -> _ (the latter only being possible for non-capturing closures).

Local lifetimes aren't concretely nameable, either; the only named lifetime is 'static (which this iterator isn't).


The compiler can tell you the type of any value via the error message, if you intentionally assign it to a binding of the wrong type, eg.:

let _: () = expr_you_want_the_type_of;
6 Likes

Closures don't have a type that can be spelled out syntactically. If you need that, you must coerce the closure to a concrete nameable type such as dyn FnMut(...) -> _ or fn(...) -> _ (the latter only being possible for non-capturing closures).

I am still not able to follow what you suggest, can please show me the guiding code for this specific case? Thank you.

The reference defines closure types as

A closure expression produces a closure value with a unique, anonymous type that cannot be written out. A closure type is approximately equivalent to a struct which contains the captured variables

The coercion rules for closures paramagnetic was referring to can be found on the same page.

I don't really understand what guiding code you are looking for, sorry. I merely stated the fact that it is not possible to explicitly spell out the type of a closure.

Full code may be helpful here:

use std::iter::Map;
use std::slice::Iter;

fn main() {
    let names_str = vec![   "AAA", "BBB", "CCC", "DDD"];
    let map_len: Map<Iter<&str>, fn(&&str) -> usize> = names_str.iter().map( |name: &&str| name.len() );
}

Is this what you needed?

1 Like

Thanks, but already I tried that type declaration but can't compile. I also followed compiler's guide but no success.

 --> src/bin/example_01.rs:31:15
   |
31 |     let name: Map<Iter<&str>, Fn(&&str) -> usize> = 
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn for<'a, 'b> Fn(&'a &'b str) -> usize`
note: required by a bound in `Map`
  --> /root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/adapters/map.rs:62:19
   |
62 | pub struct Map<I, F> {
   |                   ^ required by this bound in `Map`

error[E0308]: mismatched types
  --> src/bin/example_01.rs:32:13
   |
31 |     let name: Map<Iter<&str>, Fn(&&str) -> usize> = 
   |               ----------------------------------- expected due to this
32 |             names_str.iter().map(|name: &&str| { name.len() });
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `dyn Fn`, found closure
   |
   = note: expected struct `Map<std::slice::Iter<'_, &_>, dyn for<'a, 'b> Fn(&'a &'b str) -> usize>`
              found struct `Map<std::slice::Iter<'_, &_>, {closure@src/bin/example_01.rs:32:34: 32:47}>`

error[E0277]: the size for values of type `dyn for<'a, 'b> Fn(&'a &'b str) -> usize` cannot be known at compilation time
   --> src/bin/example_01.rs:34:23
    |
34  |     println!("{:#?}", name);
    |               -----   ^^^^ doesn't have a size known at compile-time
    |               |
    |               required by a bound introduced by this call
    |
    = help: the trait `Sized` is not implemented for `dyn for<'a, 'b> Fn(&'a &'b str) -> usize`, which is required by `Map<std::slice::Iter<'_, &str>, dyn for<'a, 'b> Fn(&'a &'b str) -> usize>: Debug`
    = help: the trait `Debug` is implemented for `Map<I, F>`
    = note: required for `Map<std::slice::Iter<'_, &str>, dyn for<'a, 'b> Fn(&'a &'b str) -> usize>` to implement `Debug`
note: required by a bound in `core::fmt::rt::Argument::<'a>::new_debug`
   --> /root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/rt.rs:100:29
    |
100 |     pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'_> {
    |                             ^^^^^ required by this bound in `Argument::<'a>::new_debug`
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0782]: trait objects must include the `dyn` keyword
  --> src/bin/example_01.rs:31:31
   |
31 |     let name: Map<Iter<&str>, Fn(&&str) -> usize> = 
   |                               ^^^^^^^^^^^^^^^^^^
   |
help: add `dyn` keyword before this trait
   |
31 |     let name: Map<Iter<&str>, dyn Fn(&&str) -> usize> = 
   |                               +++

Fn(&&str) -> usize, with a capital F, is not the same thing as lower-case fn(&&str) -> usize.

The lower-case one is a function pointer. You can use it just like that.

The upper-case one is the Fn trait. To use it, you should box it.


use std::iter::Map;
use std::slice::Iter;

fn main() {
    let names_str = vec![   "AAA", "BBB", "CCC", "DDD"];
    let map_len: Map<Iter<&str>, Box<dyn Fn(&&str) -> usize>> = names_str.iter().map( Box::new(|name: &&str| name.len() ));
}
2 Likes

That's great! The real secret sauce is the use of Box<...>. Thank you.

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.