h1990
h1990

Reputation: 155

Rust create a vector of custom struct type

I'm using config-rs crate. I want to set an array to a default value in my configuration. I want to use set_default() method from the crate that accepts an argument of type Value<Array> https://docs.rs/config/latest/config/builder/struct.ConfigBuilder.html#method.set_default

I'm new to rust and having a hard time as to how I can quickly create a vector<Value>

 let default: Vec<ValueKind>= vec![1,2,3];// Errors 
 let default: Vec<Value>= vec![1,2,3]; // Errros

Upvotes: 1

Views: 1625

Answers (1)

Locke
Locke

Reputation: 8934

If you want to create a Vec<T>, the items have to be of type T. Rust does not perform implicit conversions so you need to write a little more code to make this work. It won't even allow implicit conversions between primitive types (Ex: i32 to i64).

For this, you can create a new Value or ValueKind by using From. I know this can be done because the documentation states that ValueKind implements From<i32>. The same thing also applies to Value, but it is much harder to spot when reading through the documentation.

// Same applies to `Value`.
let default: Vec<ValueKind> = vec![ValueKind::from(1), ValueKind::from(2), ValueKind::from(3)];

To make this easier, you also have a few other options. Into is implemented automatically for all types implementing From, we can replace the lengthy ValueKind::from(1) with a shorter 1.into() call.

let default: Vec<ValueKind> = vec![1.into(), 2.into(), 3.into()];

If you have a lot of values you could also choose to use an iterator to convert an array of values all in one go.

let default: Vec<ValueKind> = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    .into_iter()
    .map(|x| ValueKind::from(x))
    .collect();

That being said, I am somewhat surprised the crate authors did not give the option to use Vec<i32> as-is (Though I have not checked the documentation on this since I do not know how it is used)*. It is not too difficult to write a generic function which accepts any iterable type like a Vec, array, or a bunch of other things, and turn it into ValueKind or Value as it goes.

/// Takes some iterable value and turns it into a Vec<ValueKind>.
pub fn to_valuekind<A, T>(values: A) -> Vec<ValueKind>
where
    A: IntoIterator<Item = T>,
    ValueKind: From<T>,
{
    values.into_iter().map(|x| ValueKind::from(x)).collect()
}

*Looks like it is a restriction on how set_default functions. It accepts any Into<Value>, but by doing so they can't also implement across IntoIterator since it could theoretically cause a conflict if a type implemented both Into<Value> and IntoIterator<T> where T: Into<Value>.

Upvotes: 5

Related Questions