Am I casting too much?

blov · · 656 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hello, I am working to write a library to interface with a very old proprietary TCP protocol and I don&#39;t think I am doing this right...</p> <pre><code>func (c *CobHeader) SetKeyBody(body []byte) { copy(c.Key[1:], body[:int(math.Min(float64(len(body)), 17))]) } </code></pre> <p>Where CobHeader is the message frame (struct) I need to populate and CobHeader.Key is a 18 byte array.</p> <p>In this method I am trying to set bytes 1-&gt;18 to a variable length byte array (body)</p> <p>Is there a better way todo this?</p> <p>I feel like I did alot of int/float64 casting to get this done...</p> <hr/>**评论:**<br/><br/>weberc2: <pre><p>Don&#39;t use <code>math.Min</code>. Use this instead:</p> <pre><code>func min(a, b int) int { if a &lt; b { return a } return b } </code></pre> <p>This gives you: <code>body[:min(len(body), 17)]</code></p> <p>EDIT: Just curious, why the downvote(s)?</p></pre>twek: <pre><p>Makes sense, but feels weird going outside the standard libraries for something so simple</p></pre>weberc2: <pre><p>Yeah, it seems like that should exist. On the other hand, it&#39;s hardly more work to write that than it is to do the import and use it. :/</p></pre>ergotayours: <pre><p>If there&#39;s a function that seems as if it should be in the standard library but isn&#39;t, it&#39;s usually because of the lack of generics.</p> <p>In this case, there would have to be a MinInt, MinInt64, MinInt32 and so on, and the standard library generally avoids patterns like this, for better or worse.</p></pre>Testiclese: <pre><p>This is (sadly) considered good Go practice. Lots of core Go packages re-implement methods (look at the http package and its copy-pasta of various &#34;strings&#34; functions) because it&#39;s considered better to duplicate some code than to add a package dependency.</p> <p>Re-implementing the &#34;min&#34; function would actually be the recommended approach by the core Go team, I bet money on it. </p></pre>bmurphy1976: <pre><p>Yeah, this drives me <em>crazy</em>. I understand the lack of generics, some things are hard and there are tradeoffs. But the lack of min/max funcs for all the numeric types (and time.Duration, don&#39;t forget that one!!) is infuriating. I wrote my own. It wasn&#39;t so bad, but it was time I could have spent doing something else.</p></pre>twek: <pre><p>What I haven&#39;t figured out yet is type deff&#39;ing. </p> <pre><code>type MyType [4]byte </code></pre> <p>If I still want to use it as a byte array and grab the 2nd element do I have to convert? Like [4]byte(MyType)[1]</p></pre>SteveMcQwark: <pre><p>Nope. Named array types support all the same operations as unnamed array types. There&#39;s very limited situations where a named type can&#39;t be used where the underlying type might be. The only examples I can think of are that named pointer types don&#39;t have methods, and of course any two named non-interface types won&#39;t be assignment compatible regardless of their underlying types. Also, most binary operators (bit shifts aside) are between values of the same type.</p></pre>weberc2: <pre><blockquote> <p>I understand the lack of generics</p> </blockquote> <p>Well, that makes one of us!</p></pre>wbyte: <pre><p>Don&#39;t try so hard to fit it all on one line. It would also be wise to give those constants more significance and meaning in the program as it&#39;s probably an important part of the protocol. For example:</p> <pre><code>const ( KeyBodyOffset = 1 KeyBodyLen = 17 ) func (c *CobHeader) SetKeyBody(body []byte) { count := len(body) if count &gt; KeyBodyLen { count = KeyBodyLen } copy(c.Key[KeyBodyOffset:], body[:count]) } </code></pre> <p>However, your code (and, by extension, my example) may have a bug:</p> <blockquote> <p>CobHeader.Key is a 18 byte array. In this method I am trying to set bytes 1-&gt;18 to a variable length byte array (body)</p> </blockquote> <p>An 18 byte array has bytes 0 -&gt; 17. Depending on what your question is really asking once you&#39;ve resolved that inconsistency, you may need to alter my example to fit.</p> <p><em>Edit: fixed code style.</em></p></pre>twek: <pre><p>Well that was why I was using math.Min</p></pre>xargon7: <pre><p>Incidentally, math.Min is more complex than the trivial implementation you can have with integers since it has to deal with +/- Inf, +/- 0, and NaN. The casting is actually less efficient because of this, but insignificantly so.</p></pre>wbyte: <pre><p>Sure but, assuming it&#39;s a <code>[18]byte</code>, if you want to use the full width of <code>c.Key</code> you&#39;ll need to use <code>c.Key[0:18]</code> as the copy destination (or <code>c.Key[:]</code> which is a more convenient way to slice a whole array).</p></pre>froggert: <pre><p>FYI, your constant variable capitalization does not follow Go convention. See <a href="https://github.com/golang/go/wiki/CodeReviewComments#mixed-caps" rel="nofollow">https://github.com/golang/go/wiki/CodeReviewComments#mixed-caps</a>.</p></pre>wbyte: <pre><p>Thanks, edited.</p></pre>tallenigma: <pre><p>Just for clarification:</p> <p>Casting does not exist in Go - only type <a href="https://golang.org/ref/spec#Type_assertions">assertions</a> &amp; <a href="https://golang.org/ref/spec#Conversions">conversions</a></p> <ul> <li>Casting means that you&#39;re <em>treating</em> one type like another</li> <li>Conversion means that you&#39;re explicitly <em>converting</em> one type <em>into</em> another</li> </ul></pre>twek: <pre><p>Nice distinction to make. Are those conversations efficient enough to use &#34;willy nilly&#34;?</p></pre>SteveMcQwark: <pre><p>Converting between types with the same underlying type is trivial, since nothing has to be done to the value. Some conversions involve allocation, such as between byte slices and strings, or from a non-pointer type to an interface. Converting between strings and rune slices also involves encoding/decoding utf-8.</p></pre>adam_0: <pre><p>Conversions are generally not <em>that</em> efficient. I only use them when I need to</p></pre>Testiclese: <pre><p>A conversion is different from a cast because it will create a <em>copy</em>. C-style casts are like &#34;hey, trust me on this, this type is just like that other type&#34; and Go conversions literally create a copy of the value you&#39;re converting from - so they&#39;re usually &#34;cheap&#34; but not necessary &#34;free&#34; like casts. </p></pre>hayzeus: <pre><p>You&#39;d be better off maybe writing your own min function. You are basically only doing that much casting because you want to use Math.min, which is kind of ugly and not needed. </p> <p>You could also just use <a href="https://godoc.org/github.com/cznic/mathutil">https://godoc.org/github.com/cznic/mathutil</a>, which has a min int method </p></pre>

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

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