[英]How should I use storage class specifiers like ref, in, out, etc. in function arguments in D?
There are comparatively many storage class specifiers for functions arguments in D, which are: D中的函数参数有相对多的存储类说明符,它们是:
in
(which is equivalent to const scope
) in
(相当于const scope
) out
ref
scope
lazy
const
immutable
shared
inout
What's the rational behind them? 他们背后的理性是什么? Their names already put forth the obvious use. 他们的名字已经提出了明显的用途。 However, there are some open questions: 但是,有一些悬而未决的问题:
ref
combined with in
for struct
type function arguments by default? 默认情况下,我应该使用ref
结合in
for struct
type函数参数吗? out
imply ref
implicitely? 难道out
暗示ref
隐含? ref
on classes and/or interfaces make sense? 类和/或接口上的ref
是否有意义? (Class types are references by default.) (默认情况下,类类型是引用。) ref
on array slices? 如何对阵列切片进行ref
? const
for built-in arithmetic types, whenever possible? 我应该尽可能使用const
作为内置算术类型吗? More generally put: When and why should I use which storage class specifier for function argument types in case of built-in types, arrays, structs, classes and interfaces? 更一般地说:在内置类型,数组,结构,类和接口的情况下,何时以及为什么我应该使用哪个存储类说明符用于函数参数类型? (In order to isolate the scope of the question a little bit, please don't discuss shared
, since it has its own isolated meaning.) (为了稍微区分问题的范围,请不要讨论shared
,因为它有其独立的含义。)
I wouldn't use either by default. 我不会默认使用。 ref
parameters only take lvalues, and it implies that you're going to be altering the argument that's being passed in. If you want to avoid copying, then use const ref
or auto ref
. ref
参数只接受左值,这意味着你将改变传入的参数。如果你想避免复制,那么使用const ref
或auto ref
。 But const ref
still requires an lvalue, so unless you want to duplicate your functions, it's frequently more annoying than it's worth. 但是const ref
仍然需要一个左值,所以除非你想复制你的函数,否则它通常比它的价值更令人讨厌。 And while auto ref
will avoid copying lvalues (it basically makes it so that there's a version of the function which takes an lvalues by ref
and one which takes rvalues without ref
), it only works with templates, limiting its usefulness. 而auto ref
将避免复制左值(它基本上使得它有一个函数的版本,它接受ref
的lvalues和一个不带ref
rvalues),它只适用于模板,限制了它的用处。 And using const
can have far-reaching consequences due to the fact that D's const
is transitive and the fact that it's undefined behavior to cast away const
from a variable and modify it. 使用const
会产生深远的影响,因为D的const
是可传递的,并且事实上它是从变量中抛弃const
并修改它的未定义行为。 So, while it's often useful, using it by default is likely to get you into trouble. 因此,虽然它通常很有用,但默认使用它可能会让你陷入困境。
Using in
gives you scope
in addition to const
, which I'd generally advise against. 使用in
为const
提供scope
,我通常建议不要使用const
。 scope
on function parameters is supposed to make it so that no reference to that data can escape the function, but the checks for it aren't properly implemented yet, so you can actually use it in a lot more situations than are supposed to be legal. 函数参数的scope
应该使它不会引用该数据,但是对它的检查还没有正确实现,所以你实际上可以在很多情况下使用它而不是合法的。 There are some cases where scope
is invaluable (eg with delegates, since it makes it so that the compiler doesn't have to allocate a closure for it), but for other types, it can be annoying (eg if you pass an array be scope
, then you couldn't return a slice to that array from the function). 在某些情况下, scope
是非常宝贵的(例如,使用委托,因为它使得编译器不必为它分配闭包),但对于其他类型,它可能很烦人(例如,如果传递数组是scope
,然后您无法从该函数返回切片到该数组)。 And any structs with any arrays or reference types would be affected. 任何包含任何数组或引用类型的结构都会受到影响。 And while you won't get many complaints about incorrectly using scope
right now, if you've been using it all over the place, you're bound to get a lot of errors once it's fixed. 虽然你现在不会有很多关于错误使用scope
抱怨,如果你一直在使用它,你一定会在修复后遇到很多错误。 Also, its utterly pointless for value types, since they have no references to escape. 此外,它对于值类型完全没有意义,因为它们没有提到逃避。 So, using const
and in
on a value type (including structs which are value types) are effectively identical. 因此, in
值类型(包括值类型的结构)上使用const
和in
实际上是相同的。
out
is the same as ref
except that it resets the parameter to its init
value so that you always get the same value passed in regardless of what the previous state of the variable being passed in was. out
与ref
相同,只是它将参数重置为其init
值,这样无论传入的变量的先前状态如何,您始终都会获得相同的值。
Almost always as far as function arguments go. 几乎总是就函数参数而言。 You use const
or scope
or whatnot when you have a specific need it, but I wouldn't advise using any of them by default. 当你有特定的需要时,你使用const
或scope
或whatnot,但我不建议默认使用它们中的任何一个。
Of course it does. 当然可以。 ref
is separate from the concept of class references. ref
与类引用的概念是分开的。 It's a reference to the variable being passed in. If I do 它是对传入的变量的引用。如果我这样做的话
void func(ref MyClass obj) { obj = new MyClass(7); } auto var = new MyClass(5); func(var);
then var will refer the newly constructed new MyClass(7)
after the call to func
rather than the new MyClass(5)
. 然后var将在调用func
而不是new MyClass(5)
之后引用新构造的new MyClass(7)
new MyClass(5)
。 You're passing the reference by ref
. 你通过ref
传递引用。 It's just like how taking the address of a reference (like var
) gives you a pointer to a reference and not a pointer to a class object. 这就像获取引用的地址(如var
)为您提供指向引用的指针而不是指向类对象的指针。
MyClass* p = &var; //points to var, _not_ to the object that var refers to.
Same deal as with classes. 和班级一样的交易。 ref
makes the parameter refer to the variable passed in. eg ref
使参数引用传入的变量。例如
void func(ref int[] arr) { arr ~= 5; } auto var = [1, 2, 3]; func(var); assert(var == [1, 2, 3, 5]);
If func
didn't take its argument by ref
, then var
would have been sliced, and appending to arr
would not have affected var
. 如果func
没有通过ref
接受它的参数,则var
将被切片,并且附加到arr
将不会影响var
。 But since the parameter was ref
, anything done to arr
is done to var
. 但由于参数是ref
,所以对arr
做的任何事都是对var
。
That's totally up to you. 这完全取决于你。 Making it const
makes it so that you can't mutate it, which means that you're protected from accidentally mutating it if you don't intend to ever mutate it. 使它成为const
使得你不能改变它,这意味着如果你不打算改变它,你就会受到保护而不会意外地改变它。 It might also enable some optimizations, but if you never write to the variable, and it's a built-in arithmetic type, then the compiler knows that it's never altered and the optimizer should be able to do those optimizations anyway (though whether it does or not depends on the compiler's implementation). 它也可以启用一些优化,但是如果你从不写入变量,并且它是内置的算术类型,那么编译器就知道它永远不会改变,优化器应该能够进行那些优化(不管它是否确实如此)不取决于编译器的实现)。
immutable
and const
are effectively identical for the built-in arithmetic types in almost all cases, so personally, I'd just use immutable
if I want to guarantee that such a variable doesn't change. 对于几乎所有情况下的内置算术类型, immutable
和const
实际上是相同的,所以我个人认为,如果我想保证这样的变量不会改变,我只使用immutable
变。 In general, using immutable
instead of const
if you can gives you better optimizations and better guarantees, since it allows the variable to be implicitly shared across threads (if applicable) and it always guarantees that the variable can't be mutated (whereas for reference types, const
just means only that that reference can't mutate the object, not that it can't be mutated). 通常,如果可以使用immutable
而不是const
则可以为您提供更好的优化和更好的保证,因为它允许跨线程隐式共享变量(如果适用),并且它始终保证变量不能被变异(而对于参考) types, const
只表示该引用不能改变对象,而不是它不能被改变)。
Certainly, if you mark your variables const
and immutable
as much as possible, then it does help the compiler with optimizations at least some of the time, and it makes it easier to catch bugs where you mutated something when you didn't mean to. 当然,如果你尽可能地标记你的变量const
和immutable
,那么它确实至少在某些时候帮助编译器进行优化,并且它可以更容易地捕获你不想改变的东西。 It also can make your code easier to understand, since you know that the variable is not going to be mutated. 它还可以使您的代码更容易理解,因为您知道变量不会被变异。 So, using them liberally can be valuable. 因此,大量使用它们可能很有价值。 But again, using const
or immutable
can be overly restrictive depending on the type (though that isn't a problem with the built-in integral types), so just automatically marking everything as const
or immutable
can cause problems. 但同样,使用const
或immutable
可能过于严格,具体取决于类型(虽然这不是内置整数类型的问题),因此只需将所有内容自动标记为const
或immutable
就会导致问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.