Interface variables

February 9, 2023


… Variables of interface type also have a distinct dynamic type, which is the (non-interface) type of the value assigned to the variable at run time (unless the value is the predeclared identifier nil, which has no type). The dynamic type may vary during execution but values stored in interface variables are always assignable to the static type of the variable.

We haven’t really talked about interfaces yet, as that’s coming up in the next section of the spec about types. For now, I want to just make a couple points, to help avoid some common confusion about interfaces in Go.

Most important, an interface is its own type. It’s not some sort of type filter (something like that exists with Generics, which we’ll talk about in due course). This is important, because a lot of Go newcomers seem to think that an interface, and a type that implements an interface, ought to be interchangeable. They are not. Example:

var x interface{}  // The empty interface is implemented by all other types,
                   // since all types contain the complete list (of 0) methods
                   // in the interface

x = int(3) // This is valid; we've given our variable x, of type interface{},
           // a value of int(3)

var y int = x // This is not valid. Although x's underlying dynamic type is int,
              // x itself is of type interface{}, and not assignable to y which
              // is of type int.

x = string("foo") // Also valid; Now x's dynamic type is string. This obviously
                  // cannot be assigned to an int.

This seems to confuse people most often with regard to function calls. Let me demonstrate:

func add(a, b int) int {
	return a+b

var x interface{}

x = int(3)
var y = int(5)

sum := add(x, y) // Invalid; x is of type interface{}, while y is of type int

Let’s concluded today with some of the examples provided inline in the spec:

var x interface{}  // x is nil and has static type interface{}
var v *T           // v has value nil, static type *T
x = 42             // x has value 42 and dynamic type int
x = v              // x has value (*T)(nil) and dynamic type *T

Quotes from The Go Programming Language Specification, Version of January 19, 2023

Share this

Related Content

Empty structs

We finally we have enough knowledge for the EBNF format not to seem completely foreign, so let’s jump back and take a look at that, with the examples provided in the spec… Struct types … StructType = "struct" "{" { FieldDecl ";" } "}" . FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] . EmbeddedField = [ "*" ] TypeName [ TypeArgs ] . Tag = string_lit . // An empty struct.

Struct tags

Struct types … A field declaration may be followed by an optional string literal tag, which becomes an attribute for all the fields in the corresponding field declaration. An empty tag string is equivalent to an absent tag. The tags are made visible through a reflection interface and take part in type identity for structs but are otherwise ignored. struct { x, y float64 "" // an empty tag string is like an absent tag name string "any string is permitted as a tag" _ [4]byte "ceci n'est pas un champ de structure" } // A struct corresponding to a TimeStamp protocol buffer.

Struct method promotion

Yesterday we saw an example of struct field promotion. But methods (which we haven’t really discussed yet) can also be promoted. Struct types … Given a struct type S and a named type T, promoted methods are included in the method set of the struct as follows: If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.