When should I mutate a parameter vs assigning via a returned value

polaris · · 954 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I read some code today that passed a pointer <code>str</code> into a function and mutated it, rather than returning the value and setting it.</p> <p>Passing a pointer that you expect to mutate seems like it produces harder to read code because now to truly understand it, I must dig into the function/code and keep a tally on everything going on. I&#39;m wondering if I&#39;m crazy in thinking this.</p> <hr/>**评论:**<br/><br/>danredux: <pre><p>It helps avoid multiple <strong>sources of truth</strong>.</p> <p>Suppose you have a bank machine that can withdraw from an account, assuming the account has the funds...</p> <pre><code>cash, newAmt := bank.Withdraw(100).From(account.Amount) account.Amount -= cash </code></pre> <p>Versus</p> <pre><code>cash := bank.Withdraw(100).From(&amp;account.Amount) </code></pre> <p>You can see how, in the first example, you might forget to withdraw the funds from the account. It reduces bugs and complexity if functions start and end in valid states, where possible.</p></pre>gentleman_tech: <pre><p>Generally speaking, yes, it&#39;s much better to return values rather than mutate parameters.</p> <p>However, for some cases, it&#39;s acceptable. For example the database scan method copies results into the destination parameter. I believe this is to avoid returning an interface{} that the caller would then need to cast to an appropriate type: passing the type in as a parameter avoids this pain. </p> <p>But for your example, it seems like this is a bad idea. The function called would need to be very careful that it actually mutated the string in-place, as opposed to creating a new string at a new memory location and changing the parameter value to the new pointer, which wouldn&#39;t get returned and would not do what was expected at all. Without knowing anything about the problem it&#39;s trying to solve, it seems like this is really counter-productive.</p></pre>tex0: <pre><p>One important use case is performance, i.e. GC pressure. If you suffer from high GC pressure and want to reduce the number of allocations you may want to reuse some allocations via a buffer. If a function mutates a parameter instead of allocating and returning one this becomes possible.</p> <p>I admit this is a rather exotic use case.</p></pre>Redundancy_: <pre><p>You can see this style in the hashing function Sum(), which takes an output slice to enable you to avoid allocation (iirc)</p></pre>echophant: <pre><p>Another example from the standard library is <code>io.Reader</code>, which could just as easily have been defined as <code>Read() (p []byte, err error)</code>, but takes in a slice to avoid the extra allocation.</p></pre>mcouturier: <pre><p><code>io.Reader</code> is a good example: it takes a slice (the container) and returns the bytes read count and an error.</p> <p>Same thing could be done with a string. Like a function that extracts something into the string and returns a pair &#34;where it found it and an error&#34;. IDK. Strings are immutable though so maybe the only reason to do it with a string is to not return 3 parameters.</p> <p>Edit: written -&gt; read </p></pre>demitriousk: <pre><p>I once copied and modified the code for a bytes.Reader - that was being passed to a library for format parsing - to increment an integer via a pointer so that the current offset of the data could be recorded for a resumable save state.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

954 次点击  
加入收藏 微博
0 回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传