Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do tuple structs and enum variants behave like functions [closed]

Tags:

rust

It looks like it's about binding a type constructor to a variable, but I haven't seen in in a wild and compiler accepts it like it's normal. So that's why I'm asking.

Thanks in advance!

link to playgroud


#[derive(Debug)]
struct B(u8);

#[derive(Debug)]
enum E {
    A(u8),
}

fn main() {
    let y = E::A;
    let y = y(0);
    dbg!(y);

    let x = B;
    let x = x(0);
    dbg!(x);

    // uncomment to see compiler complain
    // let c: fn(u8) -> u8 = B;
}

UPD: Just recalled what made me curious. It's code block from Rust 1.66.0 Announce, which I also find very confusing.

#[repr(u8)]
enum Foo {
    A(u8),
    B(i8),
    C(bool) = 42,
}
like image 658
Dblm0 Avatar asked Sep 02 '25 17:09

Dblm0


2 Answers

They behave like that because the compiler is designed that way.

Tuple-like structs and tuple-like enum variants can both be used as zero-sized values of their respective function item type.

And those, in turn, can be coerced into function pointers, which is what c is declared as when you assign a type of fn(_) -> _.

This is documented here: The Rust Reference - Function item types.

like image 135
Lucas S. Avatar answered Sep 05 '25 16:09

Lucas S.


For tuple structs & enum variants the compiler will define a function with the same name as the struct/variant for convenience. It allows for easy wrapping of collections in a struct / variant like this:

let ints = vec![1u8, 2, 3, 4];
let bs = ints.iter().copied().map(B).collect::<Vec<_>>();
let as = ints.iter().copied().map(E::A).collect::<Vec<_>>();

It's probably also there to avoid confusion where one can just omit the parentheses for some identifiers but not for others.

like image 38
cafce25 Avatar answered Sep 05 '25 16:09

cafce25