为什么在Go语言中,hashsum、encode、print与write、hashum、encode、print不同?

huangapple go评论74阅读模式
英文:

Confused about why hashsum, encode, print is different then write, hashum, encode, print in Go?

问题

抱歉,关于标题的问题。我无法想出更好的表达方式,如果有其他人能提供,我会很乐意修改。

Hasher的定义如下:

hasher := md5.New()

无论如何,我很好奇为什么这段代码:

fmt.Println(hex.EncodeToString(hasher.Sum([]byte(input))))

输出的结果是6869d41d8cd98f00b204e9800998ecf8427e,而这段代码:

hasher.Write([]byte(input))
fmt.Println(hex.EncodeToString(hasher.Sum(nil)))

输出的结果是49f68a5c8493ec2c0bf489821c21fc3b,还有这段代码:

fmt.Printf("%x\n", md5.Sum([]byte(input)))

输出的结果是49f68a5c8493ec2c0bf489821c21fc3b。

英文:

Sorry about the title. I couldn't come up with a better way of phrasing my question and will change it happily if somebody else can.

Hasher is defined with

hasher := md5.New()

Anyway, I am curious why this:

fmt.Println(hex.EncodeToString(hasher.Sum([]byte(input))))

gives me 6869d41d8cd98f00b204e9800998ecf8427e, while this:

hasher.Write([]byte(input))
fmt.Println(hex.EncodeToString(hasher.Sum(nil))

gives me 49f68a5c8493ec2c0bf489821c21fc3b
and this:

fmt.Printf("%x\n", md5.Sum([]byte(input)))

gives me 49f68a5c8493ec2c0bf489821c21fc3b.

答案1

得分: 1

通常,hasher.Sum() 不会对传入的切片进行哈希处理。传入的切片被用作目标:它将当前哈希追加到切片末尾,并不会改变底层的哈希状态。而hasher.Write()会将传入的切片包含在哈希计算中。这两个示例本质上是不同的,不同的结果是可以预期的。

始终阅读文档。hash.Hash.Sum()

> // Sum将当前哈希追加到b并返回结果切片。
> // 它不会改变底层的哈希状态。
> Sum(b []byte) []byte

因此,当你首次调用hasher.Sum()时,无论你传入什么,对于结果哈希来说都没有影响。如果之前没有向hasher中写入任何内容,你将看到初始哈希值。

当你接下来调用hasher.Write([]byte(input))时,你将把input的字节写入哈希器中,所以当你接下来调用hasher.Sum(nil)时,你将看到input的计算哈希值。由于你传入了nil,将会分配一个新的切片来容纳结果。

当你再次调用hasher.Write([]byte(input))时,如前所述:这不会改变哈希状态,传入的切片不会被用作输入,而只是作为“返回”结果的目标,即当前的哈希值。因此,你将得到与之前的hasher.Sum(nil)调用得到的相同的哈希值。显然,如果传入的切片没有足够的容量来存储结果,将会分配/使用一个新的切片。

请参考以下完整的可运行示例,它可以重现你的输出:

input := "hi"
hasher := md5.New()
fmt.Println(hex.EncodeToString(hasher.Sum([]byte(input))))

hasher.Write([]byte(input))
fmt.Println(hex.EncodeToString(hasher.Sum(nil)))

fmt.Printf("%x\n", md5.Sum([]byte(input)))

Go Playground上尝试一下。

英文:

Generally hasher.Sum() does not hash the passed slice. The passed slice is used as the destination: it appends the current hash to it and does not change the underlying hash state. hasher.Write() obviously includes the passed slice in the hash calculation. The 2 examples are fundamentally different, the different results are nothing but expected.

Always read the documentation. hash.Hash.Sum():

> // Sum appends the current hash to b and returns the resulting slice.
> // It does not change the underlying hash state.
> Sum(b []byte) []byte

So when you first call hasher.Sum(), whatever you pass to it, it doesn't matter in terms of the result hash. If you haven't written anything into hasher previously, you'll see the initial hash.

When you next call hasher.Write([]byte(input)), you'll write the bytes of input into the hasher, so when you call hasher.Sum(nil) next, you'll see the calculated hash of input. Since you pass nil, a new slice will be allocated to accommodate the result.

When you again call hasher.Write([]byte(input)), as previously written: this won't change the hash state, the passed slice is not used as input, but only as the destination for "returning" the result, the current hash value. So you will get the same hash value as you got from the previous hasher.Sum(nil) call. Obviously, if the passed slice does not have enough capacity to store the result, a new one will be allocated / used.

See this complete, runnable example which reproduces your output:

input := "hi"
hasher := md5.New()
fmt.Println(hex.EncodeToString(hasher.Sum([]byte(input))))

hasher.Write([]byte(input))
fmt.Println(hex.EncodeToString(hasher.Sum(nil)))

fmt.Printf("%x\n", md5.Sum([]byte(input)))

Try it on the Go Playground.

huangapple
  • 本文由 发表于 2021年8月28日 03:13:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/68958343.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定