Some Questions in Golang

Some Questions in Golang

Recording some issues meet recently. There might still have updates afterwards.

What does var _ I = (*T)(nil) mean?

Function: check if struct T has implemented the interface I with plain grammar.

Further Realization: we can separate the left and right side of the equal sign =.

Left Side: var _ I are equivalent to var variable type.

Right Side: (* T)(nil) are equivalent to var variable *T nil.

var _ I = (*T)(nil) can also be declared as var _ I = &T{}.

Let’s have some examples:

1
2
3
4
5
6
7
8
9
10
type myInterface interface {
shouldBeImplement()
}

type User struct {
Name string
Age uint8
}

var _ myInterface = (*User)(nil)

Currently we have not implemented the interface yet, so the declaration ``will report an error

1
Cannot use '(*User)(nil)' (type *User) as the type myInterfaceType does not implement 'myInterface' as some methods are missing:shouldBeImplement()

After we implement the interface, the error just soon disappear.

1
func (u *User) shouldBeImplement(){}

How does Type Assertion Work?

There are two kinds of type assertion:

The First One:

1
t := i.(T)

This expression can assert a interface object (i) is not null and the type it store is T. If the assertion succeeds, it will return value to t, or that trigger panic.

Let’s have a example:

1
2
3
4
5
6
7
8
func main() {
var i interface{} = 10
t1 := i.(int)
fmt.Println(t1)
t2 := i.(string)
fmt.Println(t2)
}

Running Result:

1
2
10
panic: interface conversion: interface {} is int, not string

The Second One:

1
t, ok:= i.(T)

This expression asserts that an interface object is not null and that the value contained in the interface object is of type T, just as the previous one. If the assertion succeed, the value of ok will be true.

If the type of interface object is not T or is null, the assertion fails. But unlike the first expression, the second one won’t trigger panic. It will set the value of ok as false.

Function Interface

Take Handler in go package net/http as example:

1
2
3
4
5
6
7
8
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type HandlerFunc func(ResponseWriter, *Request)

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}

Firstly, an interface Handler is defined, with only one method ServeHTTP(ResponseWriter, *Request) .

Then it defines a function type HandlerFunc, whose parameters and return value are the same with ServeHTTP.

Lastly it defines the method ServeHTTP of HandlerFunc, and call itself. This just implements the interface Handler.

HandlerFunc is a function type which implements interface, therefore named as function interface.

We can use http.Handle to map request path and process functions. Handle is defined as follows:

1
func Handle(pattern string, handler Handler)

Two kinds of arguments can be used to call the function interface.

The First One: import function

1
2
3
4
5
6
7
8
9
func hw(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("hello, world"))
}

func main() {
http.Handle("/hw", http.HandlerFunc(hw))
_ = http.ListenAndServe("localhost:8000", nil)
}

The Second One: import struct which implements the interface

In this way, the struct should implements the interface method: ServeHTTP

1
2
3
4
5
6
7
8
type User struct {}
func (u *User) ServeHTTP(w http.ResponseWriter, r *http.Request){}

func main() {
http.Handle("/hw", &User{})
_ = http.ListenAndServe("localhost:8000", nil)
}

To summarize, function interface can take both normal function types(need type transformation) and struct body as argument. This flexibility and readability attach great value to function interface.