Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can not convert [Size]byte to string in Go?

I have a sized byte array that I got after doing md5.Sum().

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

The error:

cannot convert b (type [16]byte) to type string

I find the solution at this problem

Change to:

pass = string(b[:])

But why can not use it like this?

pass = string(b)
like image 666
soapbar Avatar asked Jan 20 '15 08:01

soapbar


1 Answers

Short answer is because the Go Language Specification does not permit it.

Quoting from the Go Language Specification: Conversions:

A non-constant value x can be converted to type T in any of these cases:

  • x is assignable to T.
  • x's type and T have identical underlying types.
  • x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
  • x's type and T are both integer or floating point types.
  • x's type and T are both complex types.
  • x is an integer or a slice of bytes or runes and T is a string type.
  • x is a string and T is a slice of bytes or runes.

The specification only allows converting a slice of bytes or runes to string, but not an array of bytes.

Long answer

In Go arrays and slices are distinct types. The size of an array is part of the type.

Slices are much more general than arrays, and converting an array to a slice which represents the same series of values is very easy: arr[:] (and is also cheap, the result slice will share the array as its backing array, no reallocation or copying will be done).

Because of this, all functions and support are provided for slices and not for arrays.

Just image you want to create a simple function which takes a slice (with any length) of int numbers and returns the sum of the numbers. Something like this:

func sum(s []int) (sum int) {
    for _, v := range s {
        sum += v
    }
    return
}

If you would decide to use an array as the input, since the length is part of the type, you would limit the usability of your function, it could only take arrays of the same length:

func sum2(s [2]int) (sum int) {
    for _, v := range s {
        sum += v
    }
    return
}

You can call sum2() only with values of type [2]int but if you have an array of type [3]int, you can't because those 2 types are distinct! You also cannot call sum2() if you only have a slice of int's (you can't access the backing array of a slice). Meanwhile you can call your sum() function with all []int slices, and if you have an array, you can still use it by passing arr[:] to your sum() function.

Note:

Also note that converting a "random" slice of bytes to a string is most likely not what you want because a "random" slice of bytes may not be a valid UTF-8 byte sequence.

Instead use the encoding/hex package to convert the result to a hex string like this:

fmt.Println(hex.EncodeToString(b[:]))
like image 146
icza Avatar answered Sep 23 '22 08:09

icza