<p>The Sum method of hash.Hash return a byte slice.<br/>
Packages in subdirectories of crypto that provide hashes offer New functions that return implementations of hash.Hash. Create a hash with New, Write to it, call Sum(nil) and voila, you got your hash in a []byte.<br/>
They also directly provide a "convenient" Sum function witch directly hashes the data you gave it and return it to you. In an array...<br/>
Why an array ? In the case of crc32, i get that a uint32 can be more useful than a []byte but even then the function returning this uint32 and the method returning a []byte are clearly differentiated (hash.Hash.Sum vs crc32.Checksum)<br/>
But in the cases of hashes from crypto you have a function and a method looking pretty similar that have really different argument which look also pretty similar.<br/>
I was taught that the go way is to use slice most of the time and array only when they are needed. And I need some help to see why they are needed here.</p>
<hr/>**评论:**<br/><br/>bradfitz: <pre><p>hash.Hash.Sum needs to return a slice because each implementation of Hash might have a different result size.</p>
<p>But crc32 always returns 32 bits, so uint32 makes sense.</p>
<p>And md5.Sum always returns 16 bytes (128 bit hash), so it returns an array to avoid allocating. Likewise with sha1.Sum, etc.</p></pre>feeddageek: <pre><p><a href="/u/TheMerovius" rel="nofollow">/u/TheMerovius</a> reply's made me consider that arrays may live on stack while slice will probably live on heap. Was that what you meant by allocation ? Place of allocation, not amount allocated ?<br/>
I think it start to make sens to me. </p></pre>feeddageek: <pre><blockquote>
<p>And md5.Sum always returns 16 bytes (128 bit hash), so it returns an array to avoid allocating. </p>
</blockquote>
<p>Using an array to save 2 int worth of memory fell more like c than like go. </p>
<p><strong>Edit:</strong> Especially since you would have to slice that array to use it with about any function from the standard library.</p></pre>F41LUR3: <pre><p>Note the part about "avoid allocating". It's a performance concern, not so much a memory space concern, specially when you start using hashes in great number. The allocation overhead can add up really fast.</p>
<p>You're always welcome to wrap it and return what you want it to return for your use case.</p></pre>feeddageek: <pre><p>Then slice should be more efficient since array end up being copied...<br/>
Or is there something I don't understand correctly ?<br/>
<a href="https://play.golang.org/p/4tUHa8movG" rel="nofollow">https://play.golang.org/p/4tUHa8movG</a><br/>
<strong>edit:</strong> I mean it, I'm not being sarcastic. I fell there must be something I don't understand for this function to be like that and I wish to understand it.</p></pre>TheMerovius: <pre><p>If the compiler sees, that a <code>[16]byte</code> is returned, it can create 16 byte worth of space on the stack and have the function return it into that. Whereas, if a <code>[]byte</code> is returned, it doesn't know the size, so the bytes themselves need to land on the heap.</p>
<p>Now, with inlining it doesn't need to matter, though a) I don't know if the compiler is clever enough and b) you can't always inline.</p>
<p>The <code>[16]byte</code> thing doesn't even need to be a compiler optimization; it can in theory be built into the calling convention.</p>
<p>All of that being said: I'm guessing. No idea about the actual implementation here.</p>
<p>[edit] Your example isn't very illustrative, because the bytes probably escape (as you do use a slice). That being said, a simplification shows, that my guess also doesn't happen :) So, no clue.</p></pre>feeddageek: <pre><p>You are right, me taking a slice of the array and returning it forces the compiler to allocate that array on heap. But even if this array live in heap after the return of get, the array that main obtain is a fresh new copy of it (on stack this time i suppose) whereas the array referenced by the returned slice, is the same as the one that was allocated inside get, the content of that array did not need to be copied.</p></pre>JakeMolnar: <pre><p>I wrote up some benchmarks for you that might help illustrate the difference. <a href="https://github.com/TheDorkKnight/arraybench" rel="nofollow">https://github.com/TheDorkKnight/arraybench</a></p>
<p>I tried to target only the difference between returning arrays and slices in my benchmarks, though I can't guarantee for sure that my methods are sound.</p>
<p>The upshot of my results: There is a noticeable improvement in performance when we return an array on the stack (<em>BenchmarkSlice</em>), instead of allocating a slice on the heap (<em>BenchmarkArrayCopy</em>).</p>
<p>I've also included benchmarks that help us compare performance when zero copying occurs (<em>BenchmarkSliceWrappingArray</em> and <em>BenchmarkArray</em>).</p></pre>__ah: <pre><p>You would usually just store the sum, not needing to "use it with about any function from the standard library." The sum will probably be stored in a database or in some in-memory structure. You can do equality comparisons with the byte arrays, which is generally all you want out of a sum.</p>
<pre><code>var sumTable map[string][sha256.Size]byte
func check(id string, in []byte) bool {
expectedSum := sumTable[id]
newSum := sha256.Sum(in)
return newSum == expectedSum
}
</code></pre></pre>TheMerovius: <pre><p>You will likely, with cryptographic hashes, not use <code>==</code>, but use <a href="https://godoc.org/crypto/subtle#ConstantTimeCompare" rel="nofollow">subtle.ConstantTimeCompare</a>.</p></pre>Redundancy_: <pre><p>I actually find it a little confusing that md5.Sum does something different from hash.Hash.Sum</p></pre>
![](https://static.golangjob.cn/static/img/banner.png)