静态类型的定义与动态查找

On the book The Go Programming Language Phrasebook said:

If you require performance, then you can use statically typed definitions and avoid the dynamic lookup. If you require flexibility, then you can use the late binding mechanism of interfaces

Can someone explain me what "statically typed definitions" and "dynamic lookup" are for methods and functions in Go?

Imagine that we have the following code:

type A struct {}

func (a A) Foo() {
    fmt.Println("Foo called")
}

type I interface {
    Foo()
}

I can now create a variable of type A and call this method:

a := A{}
a.Foo()

The compiler knows the static type of the variable, so knows that the method call refers to the A.Foo method. So it can compile the above code to use a direct call to A.Foo, which will be as fast as a normal function call.

If instead we use a variable of type I, things are different:

var i I = A{}
i.Foo()

The variable i can hold any type that has a Foo method. In this particular case it is holding an A value, but won't necessarily know this at compile time. So instead the compiler generates code to check the dynamic type of i, look up the associated Foo method and finally call that method. This form of dispatch is slower than the first, but has the benefit the code will work for any type implementing the interface.

This is similar to C++'s distinction between virtual and non-virtual methods, except rather than the type of dispatch being fixed for a method at its definition, it depends on the type of variable you use in Go.

What the book refers to when it says using static types is using non interface types:

func Foo(v int, s string) { ... }

The other option is using interface:

func Bar(a interface{}, b interface{}) { ... }

Because with the first option, Go will know at compile time what type of value the function will retrieve (int and string in this case), it will compile the code specifically for those types.

With the second option, you will have to use reflection at runtime in order to know the values contained in the interfaces. This is a bit of overhead, but it allows you to pass different types of values as parameters to the function, thus being more dynamic.

Further reading: Laws of Reflection in Go