我应该借用还是复制我的小数据类型?

Mai*_*ein 5 rust

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)

我目前正在编写向量数学库,想知道是否应该借用或复制向量类型。

目前,我实现CopyVec目的是使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)

在性能方面,本例refcopy本例之间似乎没有区别。

Copy 似乎为图书馆用户带来了更好的人体工程学。

Mat*_* M. 9

Rust 并不是一种具有崇高美学目标和单一目的的纯粹学术语言。Rust 是一种系统编程语言,这意味着实用主义。

一般的经验法则是您的界面应正确记录所有权

  • 当你放弃所有权时按价值传递
  • 当您暂时放弃所有权时通过引用传递(可能可变)

然而,这一Copy特质是实用主义发挥作用的完美例子。它认识到通过引用传递可能很麻烦(有人想输入吗(&1 + &x) * &y?),因此为不需要仿射的类型创建了一个逃生舱口(即,对销毁没有特殊操作)。

因此,从语义上讲,如果您的类型可以保证是并保持为Copy,那么将其标记为这样可以为用户提供一些使用余地,从而改善人体工程学。那么,我鼓励您标记它,但要提醒您,稍后删除该Copy特征将是向后不兼容的更改。

一旦类型为Copy,我会毫不犹豫地利用这一事实并按值传递它。毕竟,如果该类型从不按值传递,那么Copy一开始就没有必要创建它。


唯一需要注意的是性能原因。

Copy强制复制,它只是允许复制。这意味着优化器可以自由选择是否使用副本。

对于小型类型,无论发生什么情况,性能都不太可能有太大差异;对于更大的类型,如果性能很重要,我会鼓励对各种接口进行基准测试。Vec只是 64 位架构上指针/引用大小的 1.5 倍,因此它确实处于灰色区域。有时复制会更慢(较大的副本),但有时拥有本地副本的好处将实现指针不会触发的优化。

然而,这种基准测试充满了危险,特别是因为它很大程度上取决于函数是否内联(或多或少有删除副本的余地)。


Eli*_*off 5

我建议在这种情况下借款,因为所有权似乎不是问题。所以,我猜你的代码看起来像

struct Vec {
    data: [f32; 3],
}

impl Vec {
    fn dot(&self, other: &Vec) -> f32 {..}
}
Run Code Online (Sandbox Code Playgroud)

  • *这是复制向量时发生的情况*——这可能取决于优化编译器的突发奇想,如果它决定可以对其进行简化。 (3认同)
  • 你能解释一下为什么你会推荐吗? (2认同)