Hi,
While learning Rust I stumbled upon a problem that I don't quite understand and I thought it'd be wise to reach out for help. I did find a solution but it didn't feel right (I discuss that later on).
What I want is: to build a function that takes the ownership of a generic vector, breaks its values from it, and builds a generic Struct
that has these values as coordinates. It is important to emphasize that I do not want to impose a Copy
trait bound in this function.
Below we have the Struct
that I am using.
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
As an example, our vector will be made up of String
elements.
fn main() {
// Some generic vector (with possible non-Copy types)
let v = vec![String::from("hello"), String::from("world")];
// Take ownership of the vector and consume its values so we build a new 'point'
let point: Point<String> = point_from_vec(v);
println!("point = {:?}", point); // point = Point { x: "hello", y: "world" }
}
While I did find a way to solve this problem, I have a strong feeling that:
(1) I've overlooked something (maybe simple maybe not...),
(2) there exists a much better way to approach these kind of problems,
(3) what I want to do doesn't make any sense because I should've been structuring these problems in a completely different way.
The solution I mentioned is shown below:
fn point_from_vec<T>(v: Vec<T>) -> Point<T> {
assert_eq!(v.len(), 2); // to ensure that the 'unwrap' at the end of the function won't fail
// I create a couple of mutable objects that have to be 'Options' so I can initialize the
// types that are not yet concrete.
let mut x: Option<T> = None;
let mut y: Option<T> = None;
// The idea here is to consume the vector (so I can essentially move the values out of the
// owned vector) and overwrite the variables 'x' and 'y'. Not an elegant way to do this I guess.
for (i, value) in v.into_iter().enumerate() {
if i == 0 {
x = Some(value);
} else {
y = Some(value);
}
}
Point { x: x.unwrap(), y: y.unwrap() }
}