简体   繁体   English

我应该如何在D中的函数参数中使用存储类说明符,如ref,in,out等?

[英]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中的函数参数有相对多的存储类说明符,它们是:

  • none 没有
  • 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: 但是,有一些悬而未决的问题:

  1. Should I use ref combined with in for struct type function arguments by default? 默认情况下,我应该使用ref结合in for struct type函数参数吗?
  2. Does out imply ref implicitely? 难道out暗示ref隐含?
  3. When should I use none ? 什么时候应该使用没有
  4. Does ref on classes and/or interfaces make sense? 类和/或接口上的ref是否有意义? (Class types are references by default.) (默认情况下,类类型是引用。)
  5. How about ref on array slices? 如何对阵列切片进行ref
  6. Should I use 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 ,因为它有其独立的含义。)

  1. 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 refauto 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. 使用inconst提供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值类型(包括值类型的结构)上使用constin实际上是相同的。

  2. 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. outref相同,只是它将参数重置为其init值,这样无论传入的变量的先前状态如何,您始终都会获得相同的值。

  3. 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. 当你有特定的需要时,你使用constscope或whatnot,但我不建议默认使用它们中的任何一个。

  4. 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. 
  5. 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

  6. 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. 对于几乎所有情况下的内置算术类型, immutableconst实际上是相同的,所以我个人认为,如果我想保证这样的变量不会改变,我只使用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. 当然,如果你尽可能地标记你的变量constimmutable ,那么它确实至少在某些时候帮助编译器进行优化,并且它可以更容易地捕获你不想改变的东西。 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. 但同样,使用constimmutable可能过于严格,具体取决于类型(虽然这不是内置整数类型的问题),因此只需将所有内容自动标记为constimmutable就会导致问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我应该将ref或副本分配给值返回函数吗? - Should I assign a ref or a copy to a value returning function? 我应该如何引用 Java 中“祖父”类的函数/void? - How should I reference to a function/void of the "grandparent" class in Java? 如何在Perl中使用代码ref作为回调? - How can I use a code ref as a callback in Perl? 在哪里可以找到完整的Zen Cart参考,以获取物品和类别信息等? - Where could I find a complete Zen Cart reference for getting item and category info, etc.? C#“参考”不做我认为应该做的 - C# “ref” not Doing what I Think it Should 如何在 React Navigation 标头中使用 ref - How to use ref in React Navigation header 我应该如何在函数中传递结构? - How should I pass a struct in a function? 如何使具有引用数据成员的类可以在没有参数的情况下构造? - How can I make a Class with reference data member constructible with no arguments? 我可以避免使用显式生命周期说明符而是使用引用计数(Rc)吗? - Can I avoid using explicit lifetime specifiers and instead use reference counting (Rc)? 我如何将 ref 传递给 state? - how do I pass ref to state?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM