A Tour of Go - Methods and interfaces Flashcards

1
Q

In Go, what is a method?

A

A method is a function with a special receiver argument.

The receiver appears in its own argument list between the func keyword and the method name.

You can only declare a method with a receiver whose type is defined in the same package as the method. You cannot declare a method with a receiver whose type is defined in another package (which includes the built-in types such as int).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

In Go, what is a pointer receiver?

A

You can declare methods with a pointer receiver - *T. Also, T cannot itself be a pointer.

Methods with pointer receivers can modify the value to which the receiver points.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Methods with pointer receivers and pointer indirection

A

Methods with pointer receivers take either a value or a pointer as the receiver when they are called:

var v Vertex
v.Scale(5)  // OK same as (&v).Scale(5)
p := &v
p.Scale(10) // OK
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Methods with value receivers and pointer indirection

A

Methods with value receivers take either a value or a pointer as the receiver when they are called:

var v Vertex
fmt.Println(v.Abs()) // OK
p := &v
fmt.Println(p.Abs()) // OK interpreted as (*p).Abs()
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Why choose a pointer receiver?

A
  • Modification - the first is so that the method can modify the value that its receiver points to.
  • Avoid copying - the second is to avoid copying the value on each method call. This can be more efficient if the receiver is a large struct, for example.
  • Don’t mix - In general, all methods on a given type should have either a value or pointer receivers, but not a mixture of both.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

What is an interface type?

A

An interface type is defined as a set of method signatures.

A value of interface type can hold any value that implements those methods.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Interfaces are implemented implicitly

A

A type implements an interface by implementing its methods.

There is no explicit declaration of intent, no “implements” keyword.

Implicit interfaces decouple the definition of an interface from its implementation, which could then appear in any package without prearrangement.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Under the hood, interface values can be thought of as ….

A

a tuple of a value and a concrete type:

(value, type)

An interface value holds a value of a specific concrete type.

Calling a method on an interface value executes the method of the same name on its underlying type.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Interface values with nil underlying values

A

If the concrete value inside the interface itself is nil, the method will be called with a nil receiver.

In some languages this would trigger a null pointer exception, but in Go it is common to write methods that gracefully handle being called with a nil receiver (as with the method M in this example.)

Note that an interface value that holds a nil concrete value is itself non-nil.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Can you call a method on a nil interface?

A

No. A nil interface value holds neither value nor concrete type.

Calling a method on a nil interface is a run-time error because there is no type inside the interface tuple to indicate which concrete method to call.

var i T
i.M() // runtime error
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

The empty interface

A

The interface type that specifies zero methods is known as the empty interface:

interface{}

An empty interface may hold values of any type.

Empty interfaces are used by code that handles values of unknown type.

For example, fmt.Print takes any number of arguments of type interface{}.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is a type assertion?

A

A type assertion provides access to an interface value’s underlying concrete value.

t := i.(T)

If i does not hold T, the statement will trigger a panic.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

How do you test a type assertion?

A

To test whether an interface value holds a specific type, a type assertion can return two values: the underlying value and a boolean that reports whether the assertion succeeded.

t, ok := i.(T)

if i holds a T, then t will be the underlying value and ok will be true.

If not, ok will be false and t will be the zero value of of type T, and no panic occurs.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

What is a type switch?

A

A type switch is a construct that permits several type assertions in series.

A type switch is like a regular switch statement, but the cases in a type switch specify types (not values), and those values are compared against the type of the value held by the given interface value.

switch v := i.(type) {
case T:
    // here v has type T
case S:
    // here v has type S
default:
    // no match; here v has the same type as i
}

The declaration in a type switch has the same syntax as a type assertion i.(T), but the specific type T is replaced with the keyword type.

This switch statement tests whether the interface value i holds a value of type T or S. In each of the T and S cases, the variable v will be of type T or S respectively and hold the value held by i. In the default case (where there is no match), the variable v is of the same interface type and value as i.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What is a Stringer?

A

A Stringer is a type that can describe itself as a string. The fmt package (and many others) look for this interface to print values.

type Stringer interface {
    String() string
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Errors

A

Go programs express error state with error values.

The error type is a built-in interface similar to fmt.Stringer:

type error interface {
    Error() string
}

(As with fmt.Stringer, the fmt package looks for the error interface when printing values.)

Functions ofter return an error value, and calling code should handle errors by testing whether the error equals nil.

A nil error denotes success; a non-nil error denotes failure.