string vs []byte type definition

Viewed 78

If I have this code, it works as expected:

package main
import "strconv"

type text []byte

func main() {
   hello := text("hello")
   _ = strconv.AppendQuote(hello, " world")
}

but this code fails:

package main
import "strconv"

type text string

func main() {
   hello := text("hello")
   // cannot use hello (type text) as type string in argument to strconv.Quote
   _ = strconv.Quote(hello)
}

Why does one pass and the other fail? I checked the docs [1], but I didnt see anything that explained the difference.

  1. https://go.dev/ref/spec#Type_definitions
3 Answers

What you are looking for is under Assignability:

https://go.dev/ref/spec#Assignability

In particular:

x's type V and T have identical underlying types and at least one of V or T is not a defined type.

In both cases, the underlying types are equal ([]byte is required and text is passed in case 1, string is required and text is passed in case 2), but []byte is not a defined type and string is, so it works for the first case, but not the second.

You need to piece together several definitions from the language specifications to understand what's going on:

First is Assignability:

x's type V and T have identical underlying types and at least one of V or T is not a defined type.

Then you need to examine your V and T.

In your first code snippet you have type text []byte (the V) and a function AppendQuote whose required argument is []byte (the T).

Do V and T have identical underlying types? Yes. text's underlying type is []byte by your definition, and []byte is a composite type, whose underlying type is itself. From Types:

Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself

and the paragraph just above that:

Composite types —[...] slice, [...] — may be constructed using type literals.

And, is at least one of V or T not a defined type? Yes, []byte as stated above is a composite type.

Hence a variable of type text is assignable to []byte, including passing arguments to a function.


In your second code snippet you have type text string (the V) and a function Quote whose required argument is string (the T).

Do V and T have identical underlying types? Yes. One by definition, and the other one is the predeclared type string (same quote as above).

Finally, is at least one of V or T not a defined type? No! Both are defined types. text is defined by you and string is defined by the language specs in String types:

The predeclared string type is string; it is a defined type.

So assigning text to string does not meet the conditions for assignability and it gives a compiler error.

AppendQuote accept []byte as argurment and your hello is defined as text type which is a []byte from your type definition, that is why it works.

func strconv.AppendQuote(dst []byte, s string) []byte see source code

while Quote accepts string as argument,

func strconv.Quote(s string) string see source code

And your hello type is []byte, not string. that's why it didn't work. you will either have to use the first case, or change your hello into string. e.g. _ = strconv.Quote("hello") in order for it to work.

Related