首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >函数应将sha512 256/sha512 384/sha512 512结果作为字节切片返回。

函数应将sha512 256/sha512 384/sha512 512结果作为字节切片返回。
EN

Stack Overflow用户
提问于 2018-01-02 20:18:21
回答 2查看 2K关注 0票数 1

我正在编写一个函数,该函数将输入数据作为字符串和要调用的SHA算法的位大小。它应该以字节切片的形式返回结果哈希(第一次尝试):

代码语言:javascript
复制
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")
    }
}

当然,这是行不通的:

代码语言:javascript
复制
$ 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

因此,我尝试从哈希函数的返回值中获取一个片段,在每次调用后添加[:] (第二次尝试):

代码语言:javascript
复制
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")
    }
}

这也不起作用:

代码语言:javascript
复制
$ 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)

因此,我试图获取返回值的地址,使用括号确保表达式的地址被首先取下来,然后切片(第三次尝试):

代码语言:javascript
复制
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")
    }
}

这将产生以下错误消息:

代码语言:javascript
复制
$ 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)

所以我放弃了,用额外的行来解决它(第四次尝试):

代码语言:javascript
复制
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来表达问题的解决方案。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-01-02 22:29:45

语言规范说明了关于片运算符的这一点

如果切片操作数是数组,则必须是可寻址的,并且切片操作的结果是与数组具有相同元素类型的片。

这是关于可寻址的

操作数必须是可寻址的,即变量、指针间接或切片索引操作;可寻址结构操作数的字段选择器;或可寻址数组的数组索引操作。

由此可以看出,第四次尝试是唯一有效的尝试。

下面是使用hash.Hash接口的另一种方法。

代码语言:javascript
复制
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
}
票数 1
EN

Stack Overflow用户

发布于 2018-01-02 22:10:56

重要的是,请注意,函数 (和其他SHA函数)的签名返回一个数组,这是一个与片完全不同的类型。本文清楚地解释了这种区别:Go切片:使用和内部

为了举例说明,请考虑以下几点:

代码语言:javascript
复制
x := [3]int{1, 2, 3} // x has type [3]int
y := []int(x) // ERROR: cannot convert x (type [3]int) to type []int

以下是您的每一次尝试都不起作用的原因:

  1. shaSum函数返回一个([]byte, error)的元组,但每个返回语句都试图返回([Size]byte, error),因此编译器会抱怨类型不匹配。
  2. 每个sha*.Sum*函数都返回一个([Size]byte, error)元组;您不能在这样的元组上使用[:]运算符,只能在阵列和切片上使用。
  3. 类似于上面的#2,您只能在&上使用可寻址类型操作符,它不包括函数调用(或它们返回的值,直到它们被本地存储)。
  4. 这个工作例子是惯用的。语言设计者故意选择优化,以使读者更清楚,而不是为作者简写。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48067303

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档