【发布时间】:2018-01-02 20:18:21
【问题描述】:
我正在编写一个函数,它将输入数据作为字符串以及要调用的 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 中遇到的问题。
【问题讨论】:
-
“好的解决方案”是最终的解决方案。由于错误消息中给出的原因,其他的不能工作 - 切片和字节不可互换,并且您不能像函数返回值那样获取不可寻址值的切片;你必须把它放在一个可寻址的值中,即一个变量。
-
那么秘诀不是从返回值中获取地址,而是将结果存储在函数上下文中?编辑:这不是关于语法而是关于内存管理?
-
不完全是。对数组进行切片需要在内部获取对数组的引用(地址)。
-
是的,您必须先存储该值,然后才能对其进行切片或获取指向它的指针。在您存储之前,没有地址可获取。
标签: arrays go cryptography