I illustrate this general question with an example: I have a Color-Struct which holds three u8s (Red, Green, Blue). Color has an assosiated constant Color::PREDEFINED with some predefined colors. I need an assosiated function Color::pick_one returning one of these predefined colors, depending on a given parameter:
#[derive(Clone)]
struct Color (u8, u8, u8);
impl Color {
const PREDEFINED: [Color; 3] = [
Color(90, 250, 10),
Color(120, 10, 10),
Color(40, 10, 200)
];
pub fn pick_one (param: i32) -> Color {
let index = // do some math with `param`.
Color::PREDEFINED[index]
}
pub fn to_string (&self) -> String {
format!("rgb({}, {}, {})", self.0, self.1, self.2)
}
}
Now this obviously doesn't work since pick_one returns a Color from PREDEFINED, but we cannot move out of type [Color; 3], a non-copy array.
A solution could be to clone the returned Color:
Color::PREDEFINED[index].clone()
but is this good performance?
I would also be fine with pick_one returning a &Color instead of a Color, but:
pub fn pick_one (param: i32) -> &Color {
let index = // do some math with `param`.
&Color::PREDEFINED[index]
}
gives:
missing lifetime specifier
this function's return type contains a borrowed value, but there is no value for it to be borrowed from
consider using the `'static` lifetime: `'static `
Now, is this the right place to use 'static?
I find it actually confusing that
pub fn pick_one (&self, param: i32) -> &Color {
let index = // do some math with `param`.
&Color::PREDEFINED[index]
}
works quite well – this looks a bit like the 3rd lifetime elision rule, right? But isn't the idea of this rule: A methos can't be called after self was dropped, thus, returned references to fields of self is always valid? But this isn't the point here, since PREDEFINED is not a field of self, but assosiated to Color itself, making references to PREDEFINED be valid as long as Color exists (i.e. always). And making pick_one a method is actually pointless, since always calling Color(0, 0, 0).pick_one(12) is technically possible, but doesn't make sense from a semantic point of view.
Now, what is the best way to implement such an assosiated function returning a value from an assosiated constant?