我正在编写一个函数,该函数将输入数据作为字符串和要调用的SHA算法的位大小。它应该以字节切片的形式返回结果哈希(第一次尝试):
package main
import (
"crypto/sha256"
"crypto/sha512"
"errors"
"fmt"
)
func main() {
input := "This is a test."
sha256, _ := shaSum(input, 256)
sha384, _ := shaSum(input, 384)
sha512, _ := shaSum(input, 512)
fmt.Println(input, sha256, sha384, sha512)
}
func shaSum(data string, size uint) ([]byte, error) {
input := []byte(data)
switch size {
case 256:
return sha256.Sum256(input), nil
case 384:
return sha512.Sum384(input), nil
case 512:
return sha512.Sum512(input), nil
default:
return nil, errors.New("unsupported sha size")
}
}当然,这是行不通的:
$ go run shasum.go
# command-line-arguments
./shasum.go:22:23: cannot use sha256.Sum256(input) (type [32]byte) as type []byte in return argument
./shasum.go:24:23: cannot use sha512.Sum384(input) (type [48]byte) as type []byte in return argument
./shasum.go:26:23: cannot use sha512.Sum512(input) (type [64]byte) as type []byte in return argument因此,我尝试从哈希函数的返回值中获取一个片段,在每次调用后添加[:] (第二次尝试):
func shaSum(data string, size uint) ([]byte, error) {
input := []byte(data)
switch size {
case 256:
return sha256.Sum256(input)[:], nil
case 384:
return sha512.Sum384(input)[:], nil
case 512:
return sha512.Sum512(input)[:], nil
default:
return nil, errors.New("unsupported sha size")
}
}这也不起作用:
$ go run shasum.go
# command-line-arguments
./shasum.go:22:30: invalid operation sha256.Sum256(input)[:] (slice of unaddressable value)
./shasum.go:24:30: invalid operation sha512.Sum384(input)[:] (slice of unaddressable value)
./shasum.go:26:30: invalid operation sha512.Sum512(input)[:] (slice of unaddressable value)因此,我试图获取返回值的地址,使用括号确保表达式的地址被首先取下来,然后切片(第三次尝试):
func shaSum(data string, size uint) ([]byte, error) {
input := []byte(data)
switch size {
case 256:
return (&(sha256.Sum256(input)))[:], nil
case 384:
return (&(sha512.Sum384(input)))[:], nil
case 512:
return (&(sha512.Sum512(input)))[:], nil
default:
return nil, errors.New("unsupported sha size")
}
}这将产生以下错误消息:
$ go run shasum.go
# command-line-arguments
./shasum.go:22:10: cannot take the address of sha256.Sum256(input)
./shasum.go:24:10: cannot take the address of sha512.Sum384(input)
./shasum.go:26:10: cannot take the address of sha512.Sum512(input)所以我放弃了,用额外的行来解决它(第四次尝试):
func shaSum(data string, size uint) ([]byte, error) {
input := []byte(data)
switch size {
case 256:
bytes := sha256.Sum256(input)
return bytes[:], nil
case 384:
bytes := sha512.Sum384(input)
return bytes[:], nil
case 512:
bytes := sha512.Sum512(input)
return bytes[:], nil
default:
return nil, errors.New("unsupported sha size")
}
}它最终编译并运行。现在我在想:为什么第四次尝试成功了,而其他尝试(特别是第三次尝试)却不起作用?一个好的解决方案会是什么样子?有没有办法避免像第四次那样的额外行?
编辑:我问题的根本问题不是如何将字节数组转换为字节片,而是缺乏对可寻址概念的理解,以及如何用惯用的Go来表达问题的解决方案。
发布于 2018-01-02 22:29:45
语言规范说明了关于片运算符的这一点
如果切片操作数是数组,则必须是可寻址的,并且切片操作的结果是与数组具有相同元素类型的片。
操作数必须是可寻址的,即变量、指针间接或切片索引操作;可寻址结构操作数的字段选择器;或可寻址数组的数组索引操作。
由此可以看出,第四次尝试是唯一有效的尝试。
下面是使用hash.Hash接口的另一种方法。
var hashFactory = map[int]func() hash.Hash{
256: sha256.New,
384: sha512.New384,
512: sha512.New,
}
func shaSum(data string, size int) ([]byte, error) {
f := hashFactory[size]
if f == nil {
return nil, errors.New("unsupported sha size")
}
h := f()
io.WriteString(h, data)
return h.Sum(nil), nil
}发布于 2018-01-02 22:10:56
重要的是,请注意,函数 (和其他SHA函数)的签名返回一个数组,这是一个与片完全不同的类型。本文清楚地解释了这种区别:Go切片:使用和内部。
为了举例说明,请考虑以下几点:
x := [3]int{1, 2, 3} // x has type [3]int
y := []int(x) // ERROR: cannot convert x (type [3]int) to type []int以下是您的每一次尝试都不起作用的原因:
https://stackoverflow.com/questions/48067303
复制相似问题