在Go语言中,如何将[Size]byte转换为字符串?

60

我有一个已经通过 md5.Sum() 操作得到的固定大小的字节数组。

data := []byte("testing")
var pass string 
var b [16]byte
b = md5.Sum(data)
pass = string(b)

我收到了如下错误信息:

无法将 b (类型为 [16]byte) 转换为字符串类型


6
我想指出,创建一个没有任何盐的密码是极其不安全和糟糕的想法。 - OneOfOne
8个回答

86
您可以将其称为“切片”:
pass = string(b[:])

53

稍有些晚,但请记住使用string(b[:])会打印出大部分无效字符。

如果您想像php一样获得十六进制表示形式,可以尝试使用以下内容:

data := []byte("testing")
b := md5.Sum(data)

//this is mostly invalid characters
fmt.Println(string(b[:]))

pass := hex.EncodeToString(b[:])
fmt.Println(pass)
// or
pass = fmt.Sprintf("%x", b)
fmt.Println(pass)

playground


取决于你如何打印它。 - user1804599
@OneOfOne,你确定这是正确的方法吗?当我运行你提供的游乐场脚本时,我得到了这个输出。�+�QYI��O�+��Uu ae2b1fca515949e5d54fb22b8ed95575 ae2b1fca515949e5d54fb22b8ed95575 - Nikhil Wagh
@NikhilWagh 没错,第一个打印输出将是原始校验和,不是友好的打印格式,而另外两个将是转换为十六进制的校验和。 - OneOfOne
为什么这个fmt.Println(string(b[:]))会打印出“大多数是无效数据”的结果? - pkaramol
2
这是正确的答案,以获得MD5哈希字符串。其他任何内容都没有帮助。 需要:import“encoding/hex” - ChrisG

14

这可以通过这种方式解决

pass = fmt.Sprintf("%x", b)
或者
import "encoding/base64"
pass = base64.StdEncoding.EncodeToString(b[:])

这将把它编码为base64字符串


2
在许多情况下,这是正确的答案,而不是被接受的答案。 - Ali
谢谢你提醒我,[n]byte 表示数组,而 []byte 表示切片! - rickchristie
请问您为什么在这里使用base64?问题中并没有提到base64。 - guettli

6

2023年2月1日更新

根据 unsafe: add StringData, String, SliceData,在Go 1.20中可能会弃用reflect.StringHeaderreflect.SliceHeader。而unsafe.StringDataunsafe.Stringunsafe.SliceData将取代它们,请参考1.20发行说明

unsafe包定义了三个新的函数: SliceData, String, 和 StringData。加上Go 1.17的Slice,这些函数现在提供了完整的构建和拆解切片和字符串值的能力,而不依赖于它们的确切表示。

func String2Bytes(s string) []byte {
    if s == "" {
        return nil
    }
    return unsafe.Slice(unsafe.StringData(s), len(s))
}

func Bytes2String(b []byte) string {
    if len(b) == 0 {
        return ""
    }
    return unsafe.String(unsafe.SliceData(b), len(b))
}

在 Go 1.20 之前

func Bytes2StrImp(b []byte) string {
    sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
    var s string
    sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
    sh.Data = sliceHeader.Data
    sh.Len = sliceHeader.Len
    return s
}

以上解决方案通过指针操作将字节数组转换为字符串。 string(b[:]) 将创建一个新的字符串对象,并将数据从字节数组复制到字符串。

string(b[:]) 的基准测试结果

func Bytes2StrRaw(b []byte) string {
    return string(b[:])
}

BenchmarkBytes2StrRaw-12              275305142                4.40 ns/op
BenchmarkBytes2StrImp-12              1000000000               0.315 ns/op

虽然这里有一些简单的答案,但我想提供一个更加高效的解决方案。

func Bytes2StrImp(b []byte) string{
    sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
    sh := reflect.StringHeader{
        Data: sliceHeader.Data,
        Len:  sliceHeader.Len,
    }
    return *(*string)(unsafe.Pointer(&sh)) // go vet error possible misuse reflect.StringHeader
}


能否解释一下那里发生了什么,为什么速度会快这么多? - rednafi
这段代码违反了 https://golang.org/pkg/unsafe/#Pointer 的建议:一般来说,reflect.SliceHeader 和 reflect.StringHeader 应该只被用作 *reflect.SliceHeader 和 *reflect.StringHeader,指向实际的切片或字符串,而不是普通的结构体。程序不应该声明或分配这些结构体类型的变量。 - Duncan Harris
go vet 在当前版本中也抱怨了这一点,例如在playground中尝试:https://play.golang.org/p/G6rRGp8jwtW - Duncan Harris
1
正确的代码:https://play.golang.org/p/Lh28f4HF_W9 - Duncan Harris
1
@RedowanDelowar,答案已更新。希望我表达清楚了。 - zangw

4

将其切片:

pass = string(b[:])

0
不是用于打印十六进制编码的字符串,而是在一般情况下,当[size]byte数组可能包含无效的UTF-8序列时,根据this answer,它们可以使用以下方法转换为有效的UTF-8。
s := string([]rune(string(b[:])))

示例

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    b := [1]byte{0xff}
    s := string(b[:])
    fmt.Println(s, []byte(s), utf8.Valid([]byte(s)))
    // Output: � [255] false

    s = string([]rune(string(b[:])))
    fmt.Println(s, []byte(s), utf8.Valid([]byte(s)))
    // Output: � [239 191 189] true
}

0
我发现这些评论真的没有什么帮助,因为它们假设 OP 只想要一个 []byte 的字面字符串...但如果你像我一样需要将 utf8 解码的字节作为字符串使用,你可以使用以下代码:
import  "unicode/utf8"
func bytesToUtf8(b []byte) string {
    var myString = "";
    for i := 1; i <= len(b); i++ {
        r, _ := utf8.DecodeRune(b[i-1:i])
        myString += string(r)
    }
    return myString
}
var uselessBytes := []byte{123,34,...}
helpfulUtf8String := bytesToUtf8(uselessBytes)

-3

你可以尝试一下

b.decode("utf-8")

请告诉我,这是否对您有帮助? 强调文本


2
不行,因为它不是Go语言。 - grg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接