Named tuples in Rust?

Suppose we have some intermediate data of the form (usize, usize, usize, usize, usize, usize). which represents:

x.0 = start of index into Vec A
x.1 = end of index into Vec A
x.2 = index of particular element in Vec A
x.3 = index of elem in Vec A
x.4 = index of elem in Vec B
x.5 = index of elem in Vec B

now I would much rather prefer to use:

struct {
  a_start: usize,
  a_end: usize,
  a_min: usize,
  a_max: usize,
  b_min: usize,
  b_max: usize
}

but the problem here is that we end up polluting the crate/module namespace with all these "one-off-Structs"

Question: does Rust have anything like "named tuples" or "anonymous structs" ? I want to be able to specify a name (rather than a numeric index) for the fields, but I don't want all these one-off-Structs.

struct definitions don’t need to be at the root level. It’s entirely legal to define them inside a function, for example, and the name will only be usable within the function. You can even use -> impl Trait syntax to return them if you want:


fn test(args: (usize, usize)) -> impl std::fmt::Debug {
    #[derive(Debug)]
    struct S {
        a_start: usize,
        a_end: usize,
    }
    S {
        a_start: args.0,
        a_end: args.1,
    }
}

fn main() {
    dbg!(test((3, 7)));
}

6 Likes

Yes, the Rust doesn't support anonymous structs of named fields without its own name. And I don't think polluting the crate namespace with all those one-off structs isn't that bad. If you think so, you can make another level of module boundary to hide it from the global namespace.

Some crates like the rusoto-s3 are simply full of those one-off struct definitions anyway.

5 Likes

I agree with you on this. I did not explain my reasoning well. Here is the problem:

  1. within a crate, I will have multiple functions that pass these tuples around

  2. these functions are often but not always in the same module

  3. if I define a struct, this struct needs to be visible to all these functions

  4. often times, out of laziness, to avoid pub(parent) or pub(path) ..., I just end up making it crate level visible

If you have multiple functions passing this struct around, to me it doesn't seem like it's a one-off struct. Maybe you could treat these structs are part of your crates' "internal" API.

If the struct is really only just used once, I don't think it makes much sense for it to be a struct. Is there something preventing you from making the function directly take the values as parameters? Or is it a matter of ergonomics?

use std::ops::Range;

fn foo(a_start: usize, a_end: usize, a_min: usize, a_max: usize, b_min: usize, b_max: usize) {
    // do stuff
}

// If foo's function signature seems unwieldy to you, you could try using Range
// Or RangeInclusive if that better fits your semantics
fn bar(a_bounds: Range<usize>, a_range: Range<usize>, b_range: Range<usize>) {
    // do stuff
}

fn main() {
    let a_start = 0;
    let a_end = 5;
    let a_min = 4;
    let a_max = 5;
    let b_min = 6;
    let b_max = 7;
    
    // things
    foo(a_start, a_end, a_min, a_max, b_min, b_max);
    bar(a_start..a_end, a_min..a_max, b_min..b_max);
}

3 Likes

Anonymous structs have been proposed years ago. I have no idea what has to be done to achieve progress on this issue, though:

1 Like