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