struct Vec {
data: [f32; 3],
}
impl Vec {
fn dot(&self, other: &Vec) -> f32 {
..
}
// vs
fn dot(self, other: Vec) -> f32 {
..
}
}
Run Code Online (Sandbox Code Playgroud)
我目前正在编写向量数学库,想知道是否应该借用或复制向量类型。
目前,我实现Copy的Vec目的是使API更好一些,因为您不必一直写&。
但这需要更复杂的约束,因为现在我所有的约束也都需要满足Copy。
哪一个可能产生更好的性能,为什么?
哪一个可能产生更好的人体工程学,为什么呢?
编辑:
我创建了一个小基准
test bref_f32 ... bench: 2,736,055 ns/iter (+/- 364,885)
test bref_f64 ... bench: 4,872,076 ns/iter (+/- 436,928)
test copy_f32 ... bench: 2,708,568 ns/iter (+/- 31,162)
test copy_f64 ... bench: 4,890,014 ns/iter (+/- 553,050)
Run Code Online (Sandbox Code Playgroud)
在性能方面,本例ref与copy本例之间似乎没有区别。
Copy 似乎为图书馆用户带来了更好的人体工程学。
Rust 并不是一种具有崇高美学目标和单一目的的纯粹学术语言。Rust 是一种系统编程语言,这意味着实用主义。
一般的经验法则是您的界面应正确记录所有权:
然而,这一Copy特质是实用主义发挥作用的完美例子。它认识到通过引用传递可能很麻烦(有人想输入吗(&1 + &x) * &y?),因此为不需要仿射的类型创建了一个逃生舱口(即,对销毁没有特殊操作)。
因此,从语义上讲,如果您的类型可以保证是并保持为Copy,那么将其标记为这样可以为用户提供一些使用余地,从而改善人体工程学。那么,我鼓励您标记它,但要提醒您,稍后删除该Copy特征将是向后不兼容的更改。
一旦类型为Copy,我会毫不犹豫地利用这一事实并按值传递它。毕竟,如果该类型从不按值传递,那么Copy一开始就没有必要创建它。
唯一需要注意的是性能原因。
Copy不强制复制,它只是允许复制。这意味着优化器可以自由选择是否使用副本。
对于小型类型,无论发生什么情况,性能都不太可能有太大差异;对于更大的类型,如果性能很重要,我会鼓励对各种接口进行基准测试。Vec只是 64 位架构上指针/引用大小的 1.5 倍,因此它确实处于灰色区域。有时复制会更慢(较大的副本),但有时拥有本地副本的好处将实现指针不会触发的优化。
然而,这种基准测试充满了危险,特别是因为它很大程度上取决于函数是否内联(或多或少有删除副本的余地)。
我建议在这种情况下借款,因为所有权似乎不是问题。所以,我猜你的代码看起来像
struct Vec {
data: [f32; 3],
}
impl Vec {
fn dot(&self, other: &Vec) -> f32 {..}
}
Run Code Online (Sandbox Code Playgroud)