返回关联常量数组元素的关联函数?

问题描述 投票:0回答:1

我用一个例子来说明这个一般性问题:我有一个

Color
-Struct,它包含三个
u8
(红、绿、蓝)。
Color
有一个关联的常量
Color::PREDEFINED
和一些预定义的颜色。我需要一个关联函数
Color::pick_one
返回这些预定义颜色之一,具体取决于给定参数:

#[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)
    }
}

现在这显然不起作用,因为

pick_one
Color
返回一个
PREDEFINED
,但是我们
cannot move out of type [Color; 3], a non-copy array
.

一个解决方案可能是克隆返回的颜色:

Color::PREDEFINED[index].clone()

但这是好的表现吗?

如果

pick_one
返回一个
&Color
而不是
Color
,我也可以接受,但是:

pub fn pick_one (param: i32) -> &Color {
    let index = // do some math with `param`.
    &Color::PREDEFINED[index]
}

给:

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 `

现在,这是正确的地方使用

'static
吗?

我发现它实际上令人困惑

pub fn pick_one (&self, param: i32) -> &Color {
    let index = // do some math with `param`.
    &Color::PREDEFINED[index]
}

效果很好——这看起来有点像 3rd lifetime elision rule,对吧?但是这个规则的想法是不是:在删除

self
之后不能调用方法,因此,返回对
self
字段的引用总是有效的?但这不是这里的重点,因为
PREDEFINED
不是
self
的字段,而是与
Color
本身相关联,只要
PREDEFINED
存在(即始终存在),对
Color
的引用就有效。并且使
pick_one
成为一种方法实际上毫无意义,因为总是调用
Color(0, 0, 0).pick_one(12)
在技术上是可行的,但从语义的角度来看没有意义。

现在,实现这样一个从关联常量返回值的关联函数的最佳方法是什么?

rust lifetime associated-const
1个回答
1
投票

克隆对性能有好处吗?

复制 3 个字节非常便宜。这几乎总是比引用更高效。这种廉价是

Copy
存在的原因,你应该在这里使用它:

#[derive(Clone, Copy)]
struct Color (u8, u8, u8);
pub fn pick_one (param: i32) -> Color {
    let index = ...;
    Color::PREDEFINED[index]
}

一般规则是尽可能导出

Copy

这是正确的地方使用

'static
吗?

是的。如果你要返回一个引用,并且它的生命周期不属于参数之一,它几乎总是

'static
.

pub fn pick_one (param: i32) -> &'static Color {

pick_one (&self, param: i32) -> &Color

如果您想在未来的版本中保留从

self
产生回报的能力而不破坏您的 API,则此方法才有意义。然而,这也只对非
Copy
类型有意义,所以即使你从
self
产生回报,它仍然应该是一个没有参考的直
Color


旁注:当你有一个所有相同类型的元组时,考虑做

struct Color([u8; 3])
。这在内存表示中是等效的,并为您提供
array
上的所有方法,有助于减少代码重复,例如:

let c = Color([10, 10, 10]);
let half_c = Color(c.0.map(|n| n / 2));
© www.soinside.com 2019 - 2024. All rights reserved.