我想写一些使用2D和3D点或空间方向的小库
(矢量/矩阵意义上的矢量,而不是Rust的Vec
)。
Rust在这里没有强加规则,所以你可以创建一个浮点数元组,或者一个包含x, y, z
成员的新struct
。或单个data: [f64; 3]
成员。
我想在这里定义类型而不是使用[f64; 3]
的原因是,这样我就可以声明length
, normalized
, Add
, Sub
操作符等方法。
注意,虽然有很好的现有库,我想写我自己的,因为它只需要一些基本的操作,我想了解内部发生了什么。
这个问题相当宽泛,没有一个明确的最佳方式来表达你想要什么。这在很大程度上取决于你打算用它做什么。
与其他答案相比,我将提出一个稍微不同的解决方案:使用具有x, y, z
组件的结构体,并充分使用强类型。向量可以用来表示很多东西(点,颜色,…);你谈论的是空间中的二维和三维点。首先要注意的是点矢量和方向矢量的区别。这里有一个很好的数学答案。Stackexchange很好地解释了这个话题。
这种差异可以反映在类型系统中,以捕获逻辑错误。这正是cgmath
正在做的。所以我想说,你实际上想要两种类型像这样定义:
struct Point3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
- 为什么没有元组结构或数组?写
v.x
的语义比v.0
或v[0]
要清晰得多。如果您有一个表示任意数据的向量类型,后两种情况是合适的。但是正如我提到的,我认为强类型在这里是一个很好的选择,我们应该选择相应的好名字。 - 为什么是
pub
?为什么不是?如果您谈论的是空间中的点或方向,则不存在无效向量(此处忽略NaN
浮动值)。所以没有理由限制对字段的访问。 - 为什么是
f32
?好问题…实际上,你可能应该使用类型参数,但你需要有某种trait绑定…
…好吧,这就引出了我的结论,你可能不喜欢:我认为在这种情况下,要做到正确和"习惯"需要一些努力。像cgmath
这样的库可以很好地完成这项工作。在我看来,这个cgmath
库特别有一个非常好的API设计。大多数功能是通过特征(如VectorSpace
)实现的,这些特征反映了背后的一些数学原理。我也想在我的一个项目中自己编写向量类型,但我最终被说服使用一个经过良好测试、设计良好的库来代替。
那么如何做到"正确"呢?和cgmath
差不多:
- 强类型
- 正确命名
- 在抽象特征中具有最多的功能
我建议定义一个newtype,即一个只有单个成员的元组结构体。
struct Vector3D([f64; 3]); // wraps an array
struct Vector3D((f64, f64, f64)); // wraps a 3-tuple
元组结构的字段可以通过使用它们的位置(从零开始)作为字段名来访问。例如,如果有一个类型为Vector3D
的变量v
,则v.0
将计算为内部字段。您可以选择将此字段设置为公共或不设置;要使其公开,只需在字段的类型名称之前添加关键字pub
。
struct Vector3D(pub [f64; 3]);
请注意,这个新的Vector3D
不继承任何方法或特征从包装类型;这取决于你提供任何你喜欢的API在这个类型上
正如Francis所说,您可以使用包装器类型,但如果您不需要它与其他类型真正不同,并且能够利用现有类型的方法,则可以使用类型别名:
type Vector3D = (f64, f64, f64);
或
type Vector3D = [f64; 3];