英文:
When a type is `Copy` should a method move (`self`) or borrow (`&self`) the type?
问题
在Rust中,当一个类型是Copy
时,方法应该使用移动 (self
) 还是借用 (&self
) 该类型?
对于非Copy
类型的方法调用,使用移动 (self
) 和借用 (&self
) 之间存在显著的差异。例如,你不能调用两次使用移动 (self
) 的方法。然而,对于Copy
类型,至少对于调用者来说,使用移动 (self
) 和借用 (&self
) 之间的差异变得不那么显著。
此外,由于Rust将自动进行解引用或借用以查找方法,你可以以完全相同的方式调用使用移动 (self
) 方法或引用 (&self
) 方法。
我预计这两种方法之间没有太大的区别。当由Rust编译器内联时,两者似乎生成相同的汇编代码,至少从Godbolt编译器资源管理器上的我的实验来看是这样。但是,当不内联时,生成的汇编代码可能会有所不同。这只是一个微不足道的示例,因此应该持谨慎态度。
我无法从标准库中找到一个常见的做法,因为似乎有两种做法的示例。
我认为在现实世界中,每种方法之间应该没有太大的区别,尽管这确实让我感到好奇。每当我在类型上实现Copy
时,我都会思考最佳方法是什么……
我找到了一个示例,在这个示例中,我必须同时为值和引用实现From
,否则示例将无法编译。我相信还有许多其他表现出类似行为的示例,这可能使为移动 (self
) 或借用 (&self
) 实现方法更加可取。
你认为哪种方法最好?这重要吗?是否有一种标准方法?还有其他我应该考虑的情况吗?
编辑:目前,我更倾向于在Copy
类型上使用移动 (self
)。
英文:
In Rust, when a type is Copy
, should a method move (self
) or borrow (&self
) the type?
When a method from a non-Copy
type is called, there is a significant difference between a move (self
) and a borrow (&self
). For example, you would not be able to call a method that uses move (self
) twice. However, for a Copy
type, the difference between a move (self
) and a borrow (&self
) becomes less significant, at least for the caller.
In addition, as Rust will automatically dereference or borrow to look up a method, you can call a move (self
) method or a reference (&self
) method in the exact same manner.
I expect that there is little difference in each approach. When inlined by the Rust compiler, both appear to generate identical assembly code. At least from my experiment on the Godbolt compiler explorer. However, when not inlined the assembly code generated can be different. This is a trivial example, and therefore it should be taken with a grain of salt.
I couldn't establish a common practice from the standard library as there appears to be examples of both.
I don't think there should be much difference between each approach in the real world, although it does make me curious. Every time I implement Copy
on a type, I wonder what the best approach is...
I did find an example, whereby I must implement From
for both a value and a reference, otherwise the example will not compile. I am sure there are many more examples that exhibit similar behaviour, which may therefore make it more desirable to implment methods for either move (self
) or borrow (&self
).
What do you think is best? Does it matter? Is there a standard approach? Are there other cases that I should consider?
EDIT: At the moment I prefer to use a move (self
) for Copy
types.
答案1
得分: 2
以下是翻译好的部分:
我的经验法则是:
-
如果在非
Copy
类型上实现时,该方法将消耗self
,那么对于Copy
类型,也应该采用相同的方式,因为这样更清晰和更一致。一个例子是Duration
上的算术方法,例如checked_add()
。 -
如果不是这样,那么对于小型类型(当一台机器字节(最多usize)明显很小时,而且通常情况下两个字节也很小,因为它们是成对传递的寄存器,但三个字节已经很大,因为它们在堆栈上传递),它们预计在未来版本中仍然很小,那么采用按值传递
self
,因为这样速度更快;对于其他类型(大型或可能变得大型的类型),采用&self
,因为采用self
将强制进行复制,速度会(在某种程度上)较慢。第一种类型的示例是整数、浮点数和字符的所有方法(好吧,几乎所有方法,由于遗留原因,某些
char
方法采用&self
)。第二种类型的示例是Duration
或IpAddr
上的方法。
From
是另一回事;为拥有的对象和引用都实现它是有意义的。
英文:
My rule of thumb is:
-
If, when implementing on a non-
Copy
type, this method will consumeself
, do the same forCopy
types, because it is clearer and more uniform this way. An example of this is the arithmetic methods onDuration
, e.g.checked_add()
. -
If not, then: for small types (when one machine bytes (up to usize) is definitely small, and two are usually small because they're passed in pair of registers, but three are already big because they're passed on stack) that are expected to stay small in future versions, take
self
by value because it is faster this way; for other types (big or that may become big) take&self
, because takingself
will force a copy and will be (somewhat) slower.An example of the first type is all methods on integers and floats and chars (well, almost all of them, some in
char
take&self
for legacy reasons). An example of the second type is methods onDuration
orIpAddr
.
From
is a different story; it makes sense to implement it for both owned and references.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论