第一个问题
假设我有以下结构:
#[derive(Copy, Clone, Debug)]
pub struct Vec3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Vec3 {
pub fn dot(self, v: Vec3) -> f64 { ... }
pub fn add(self, v: Vec3) -> Vec3 { ... }
...
}
我希望能够将Vec3
的使用区分为Point
(表示3D空间中的一个点)和Color
(表示RGB值)。第一步是使用类型别名:
pub type Point = Vec3;
pub type Color = Vec3;
然后在代码的其余部分,我将使用类型注解Point
和Color
来建议变量应该是什么。不过,这只是一个建议。没有什么能阻止我输入一个Color
作为参数,它的类型提示为Point
(因为在一天结束时,它们实际上只是Vec3
)。
**第一个问题:**有没有办法强制rust编译器将Point
和Color
作为不同的类型处理?
第二个问题
假设我想实现某些只能在Point
上使用的方法,然后实现另一组只能在Color
上使用的方法,例如:
impl Point {
fn point_on_line(&self, t: f64) -> Point { ... }
...
}
impl Color {
fn to_hex(self) -> String { ... }
...
}
当然,我仍然希望Color
和Point
的示例保留Vec3
中的方法。
我能想到的最简单的方法是将Vec3
转换为trait,然后为Vec3
创建Point
和Color
结构实现:
pub trait Vec3: Copy + Clone + Debug {
fn dot(self, v: Vec3) -> f64 { ... }
fn add(self, v: Vec3) -> Vec3 { ... }
...
// now requires the definition of .x(), .y(), and .z() in order
// to create default implementations for the above methods
fn x(self) -> f64;
fn y(self) -> f64;
fn z(self) -> f64;
}
#[derive(Copy, Clone, Debug)]
pub struct Point {
x: f64,
y: f64,
z: f64,
}
impl Vec3 for Point {
fn x(self) -> f64 { self.x }
fn y(self) -> f64 { self.y }
fn z(self) -> f64 { self.z }
}
当然,这需要trait在默认实现中使用.x()
来代替.x
。
**第二个问题:**是否有一个“更干净”或更习惯的方法来获得上述所需的行为?如果没有,那么通过.x(), .y(), .z()
方法进行额外的复制是否会产生任何开销(因为我们是通过一个额外的方法复制值)?我假设后一个问题的答案是否定的,因为编译器会优化它,但这是一个性能关键的应用程序,所以我只是想知道它的确切细节。
2条答案
按热度按时间cxfofazt1#
我最喜欢的一个rust技巧是使用generic来对一个结构进行不同的专业化:
因此,我不知道你的用例是否有意义,但无论如何。
ffscu2ro2#
有没有办法强制rust编译器将Point和Color视为不同的类型?
不。通常的方法是使用newtype/wrapper类型。
如果你想使用trait,你可以有一个返回
Vec3
的方法,让其余的方法有调用该方法的默认实现。这减少了重复代码的数量。我会说这是惯用的方式。
Vec3<Behavior>
的答案描述了另一种应该同样好的方法,尽管我不会说它是惯用的,因为文档并没有那么好。如果没有,通过
.x(), .y(), .z()
方法进行额外复制是否会产生任何开销由于这种getter方法被广泛使用,因此很有可能被优化。即使这些是内联的,它也可能导致其他东西不内联,从而降低速度。和往常一样,您需要在真实的数据上对完整的应用程序进行基准测试,以了解它是否有任何效果。