Function type of ctor of tuple struct with ref

Let's have this tuple struct:

struct Holder<'a>(&'a u8);

This tuple struct has the constructor with the same name:

let h: Holder = Holder(&123);

But I cannot figure out what type this constructor has (except it is a function). The following code compiles, but I want to substitute gaps with real types.

let ctor: fn(_) -> _ = Holder;
let h: Holder = ctor(&123);

I tried to use for<'a>, but it doesn't work the way I thought:

let ctor: for<'a> fn(&'a u8) -> Holder<'a> = Holder;
let h: Holder = ctor(&123);

The error hints that "concrete lifetime" != "bound lifetime":

6 |     let ctor: for<'a> fn(&'a u8) -> Holder<'a> = Holder;
  |                                                  ^^^^^^ expected concrete lifetime, found bound lifetime parameter 'a
  = note: expected type `for<'a> fn(&'a u8) -> Holder<'a>`
             found type `fn(&u8) -> Holder<'_> {Holder::<'_>}`

But I still don't have a clue how to solve the puzzle.

The playground

Initially, I wanted to accept the ctor as a (generic) function parameter, so I needed to fill Fn(_) -> _ with some types too. I'm pretty sure that doesn't differ from function pointer significantly, does it?

First time I've seen such use of constructor as function, think it is on edge of language.

Anyhow it is the inferred lifetime your after.

    fn foo<'a>(x:&'a u8) {
        let ctor = Holder::<'a> as fn(&'a u8) -> Holder<'a>;
        let h: Holder = ctor(x);
        println!("{:?}", h)

For completeness note the function is its own zero sized type to begin with and the cast is then to a more regular function pointer.

Note that this also appears when casting closures to function pointers:

fn main() {
    let f = |x: &u32| x;
    let _: fn(&u32)->&u32 = f;
error[E0308]: mismatched types
 --> src/
3 |     let _: fn(&u32)->&u32 = f;
  |                             ^ expected concrete lifetime, found bound lifetime parameter
  = note: expected type `for<'r> fn(&'r u32) -> &'r u32`
             found type `[closure@src/ 2:24]`


i.e. Holder(&123) would be considered "struct literal syntax" rather than a constructor.

The nomicon on the other hand uses the term "The One True Constructor".

Alternately, in Rust, "constructors" are just a convention:

Constructors are static (no self ) inherent methods for the type that they construct.

The constructor will like all other functions and closures have its own unique type. As for the for<'a> conversion, normally these unique types will coerce into function pointers, but the coercion doesn't seem to properly work when for<'a> is involved.

Initially I needed a way to wrap a reference into a generic holder so that

  • holder's lifetime ≠ referenced object's lifetime
  • holder constructor (aka struct initializer) is a generic function parameter

That's why I was trying to figure out the type of that function parameter. And faced with a lifetime problem.

From @jonh's answer I got the idea that I had to introduce an extra function specifically to solve this lifetime stuck, since "function with lifetime parameters" is exactly the thing to specify lifetimes =)

So I can introduce the function:

fn foo<'a, F>(x: &'a u8, ctor: F)
where F: FnOnce(&'a u8) -> Holder<'a> {
    let h = ctor(x);
    // use this "h" somehow

and then replace

let ctor: fn(_) -> _ = Holder;
let h: Holder = ctor(&123);


foo(&123, Holder);

Now I see that I had to call this function with both reference and struct ctor, otherwise compiler won't guess the (elided) lifetime of that second argument Holder of foo.

As far as I understand, there is no way to do something like this:

fn foo<F>(ctor: F)
where F: for<'a> FnOnce(&'a u8) -> Holder<'a> {
    let x = 123;
    let h = ctor(&x);
fn main() {
    foo(Holder);  // mean some Holder<'_> instead of Holder<'concrete>

Or it is possible somehow?

There happens to be a very similar question over here.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.