Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Tuple struct to function coercion : what are the lifetime parameters of said function?

I don’t understand something about the feature that makes it possible to coerce a tuple struct to a function as in:

struct MyType(u8);

let optional_mytype: Option<MyType> = Some(12).map(MyType);
//                                                 ^^^^^^ here, MyType is treated as a function

In the example above, no lifetimes are involved: everything is easy. However, when the structure has a generic lifetime bound, I’m having troubles defining the exact signature of the function it would coerce to.

Here’s a MRE of something I’ve attempted to do, and that doesn’t work (sandbox link):

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

struct MyStruct<'a>(&'a ());

// This looks, to me, like the signature the "constructor" should have
type MyStructConstructor = for<'a> fn(&'a ()) -> MyStruct<'a>;

/// Coercion problem here
fn some_code() {
    let mut constructor: MyStructConstructor = MyStruct;
}

and the error given by the type-checker:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
 --> src/lib.rs:7:48
  |
7 |     let mut constructor: MyStructConstructor = MyStruct;
  |                                                ^^^^^^^^ one type is more general than the other
  |
  = note: expected fn pointer `for<'a> fn(&'a ()) -> MyStruct<'a>`
             found fn pointer `fn(&()) -> MyStruct<'_>`

And I honestly don’t understand why my constructor type alias isn’t valid, and why the type suggested by the error message is much more lax than it should be. I mean, the lifetime <'a> of my structure should be exactly equal to that of the unit reference that is contained by the structure, not a random one.

Here‘s a more concrete (still minimal) example of what I’m actually trying to do, if having context helps you.

Thanks in advance

>Solution :

In fact, the error message might be a bit misleading. '_ does not mean any lifetime goes, it just means a lifetime I haven’t named explicitly, just as writing &() (which is the same as &'_ ()). Rust does that because that’s not the issue.

To understand, let’s actually annotate implicit generic lifetimes in your code:

fn some_code() {
  let constructor: MyStructConstructor = MyStruct<'_>;
}

Notice how something is wrong? On the right hand side, you have something whose type is generic over a lifetime. On the left hand side, you don’t.
In fact, a more appropriate constructor signature for MyStruct would be

struct MyStruct<'a>(&'a ());

type MyStructConstructor<'a> = fn(&'a ()) -> MyStruct<'a>;

fn some_code() {
  let constructor: MyStructConstructor = MyStruct;
}

leaving the lifetime implicit — see the playground.
This compiles.

So now you may understand why MyStructConstructor was more generic than MyStruct: because for MyStruct, you have to specify a lifetime to begin with, that is, the actual type is, for a given 'a, MyStruct<'a>. Then, with that constructor, you are only capable of building objects of type MyStruct<'a>, given &'a (). On the other hand, with MyStructConstructor, given a reference to a () with any lifetime, you would be able to build a MyStruct of the same lifetime, which is more general.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading