Short hand Vec/vec! initialization

I might be blind by not finding a proper short cut and the issue might not be of huge relevance,
but why do we have to take on the hustle to recall Self-returning functions in such a verbose manner?

    struct WeightedValue {...}
    ...
    let list: Vec<WeightedValue> = vec![
        WeightedValue::new(1, 1),
        WeightedValue::new(3, 4),
        WeightedValue::new(5, 8),
    ];

I have been looking for a short way, like something like this:

    let list: Vec<WeightedValue> = vec![new(1, 1),new(3, 4),new(5, 8)];

..to allow Vec<structs> to be initializes by short circuiting the initialization to Self-returning functions of the struct implementation.
or even shorter, by just providing values to fill fields - assuring type by vec-Type-definition/pattern matching on struct declaration..

    let list: Vec<WeightedValue> = vec![{1, 1},{3, 4},{5, 8}];

A different problem I can think of atm, is about str to String conversion, wouldn't it be valid to "auto-convert" this,
by copying the slice at runtime?

Even a style like Tuple-Structs would be less verbose & easier to read. - in my opinion.

Any ideas? :bulb:

Here's one way.


Rust has consciously chosen to make such costs explicit.

3 Likes

I understand the sentiment.

There are definitely ways of doing something like your first example:

You could either define a free function (either externally or even nested inside the current function) or you could create a lambda.

I'm not aware of support for (or are any plans to support) any kind of auto-convert anonymous struct declarations like in your second example. However, you could get some of what you want by using a vec/array of tuples and then mapping the new function over it.

Here is an example of all three strategies:

#[allow(dead_code)]
#[derive(Debug)]
struct WeightedValue {
    x: i32,
    y: i32,
}

impl WeightedValue {
    pub fn new(x: i32, y: i32) -> Self {
        Self { x, y }
    }
}


pub fn main() {
    let list1: Vec<WeightedValue> = vec![
        WeightedValue::new(1, 1),
        WeightedValue::new(3, 4),
        WeightedValue::new(5, 8),
    ];

    let list2 = [(1, 1), (3, 4), (5, 8)]
        .into_iter()
        .map(|(x, y)| WeightedValue::new(x, y))
        .collect::<Vec<_>>();
        
    fn new1(x: i32, y: i32) -> WeightedValue {
        WeightedValue::new(x, y)
    }
    let list3 = vec![new1(1, 1), new1(3, 4), new1(5, 8)];
    
    let new2 = |x, y| WeightedValue::new(x, y);
    let list4 = vec![new2(1, 1), new2(3, 4), new2(5, 8)];

    println!("{:?}", list1);
    println!("{:?}", list2);
    println!("{:?}", list3);
    println!("{:?}", list4);
}
2 Likes

And here's another:

let list = {
    let new = WeightedValue::new;
    vec![new(1, 1), new(3, 4), new(5, 8)]
};
4 Likes

Thank you all for the very good and extensive suggestions,
I will stick with this alias notation, as it is the least verbose and clear one :muscle:

My answer would be that you read code many more times than you write it, so we should optimise for clarity rather than saving a couple of characters.

Especially once type inference comes into the picture, let list = vec![{1, 1}, ...] is a lot harder to understand at a glance than vec![WeightedValue::new(1, 1), ...].

2 Likes

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.