struct Vec {
data: [f32; 3],
}
impl Vec {
fn dot(&self, other: &Vec) -> f32 {
..
}
// vs
fn dot(self, other: Vec) -> f32 {
..
}
}
我目前正在编写一个矢量数学库,我想知道是否应该借用或复制我的矢量类型。
目前我为Copy
实施了Vec
,这使得API更好一点,因为您不必一直写&
。
但它需要更复杂的约束,因为现在我所有的约束都需要满足Copy
。
哪一个可能产生更好的性能?为什么?
哪一个可能产生更好的人体工程学以及为什么?
编辑:
我创建了一个小microbenchmark
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)
就性能而言,此示例似乎ref
和copy
之间没有区别。
Copy
似乎为图书馆用户提供了更好的人体工程学设计。
答案 0 :(得分:4)
我建议在这种情况下借用,因为看起来似乎不是所有权。所以,我想你的代码看起来像
struct Vec {
data: [f32; 3],
}
impl Vec {
fn dot(&self, other: &Vec) -> f32 {..}
}
答案 1 :(得分:2)
Rust不是一种纯粹的学术语言,具有崇高的美学目标和独特的目的。 Rust是一种系统编程语言,意味着实用主义。
一般经验法则是您的界面应正确记录所有权:
然而Copy
特质是实用主义的完美典范。它认识到通过引用传递可能很麻烦(有人想要键入(&1 + &x) * &y
吗?)因此为不需要仿射的类型创建了一个逃生舱(即,没有特别的破坏行为)。
因此,从语义上讲,如果您的类型可以保证并保持Copy
,那么将其标记为这样可以为用户提供一些可以改善其人体工程学的余地。我会鼓励你标记它,然后,虽然提醒我后来删除Copy
特征将是一个向后不兼容的变化。
一旦类型为Copy
,我会毫不犹豫地利用这一事实并按价值传递。毕竟,如果类型永远不会按值传递,那么首先将Copy
设为Copy
是没有意义的。
唯一需要注意的是表现原因。
Vec
不强制复制,它只是允许它。这意味着优化器具有使用副本的所有自由度......或者不是。
对于小型类型,无论发生什么,性能都不太可能有所不同;对于更大的类型,如果性能很重要,我会鼓励对各种接口进save_city
只是64位体系结构上指针/引用大小的1.5倍,所以它确实处于灰色区域。有时复制会更慢(更大的副本),但有时使用本地副本的好处将启用不会被指针触发的优化。
然而,这样的基准测试充满了危险,特别是因为它在很大程度上取决于功能是否内联(取消副本的余地或多或少)。