Small tips in Go

Use the underscore to make your numbers readable

1
2
3
4
5
6
7
8
9
10
package main

import "fmt"

func main() {
number := 10000000
better := 10_000_000

fmt.Println(number == better)
}

Passing the same argument multiple times to fmt.Printf

1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
name := "Bob"
fmt.Printf("My name is %[1]s. Yes, you heard that right: %[1]s\n", name)
}

avoid deadlock in database

func GetListFollows will not release a connection in database connection pool before rows.Close, so in the
call of func GetUserDetail, there is a new need of connection, but what if every GetUserDetail is waiting
for a new connection and there is no idle connection, as the connection pool is fixed? Then there is a deadlock.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
func GetListFollows(ctx context.Context, id int) ([]*User, error) {
users := []*User{}
query := "SELECT source_id, target_id FROM follows where source_id = ?"
rows, err := sqlDB.QueryContext(ctx, query, id)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, err
}
defer rows.Close()

for rows.Next() {
follow := &Follow{}
if err := rows.Scan(&follow.SourceID, &follow.TargetID); err != nil {
return nil, err
}

user, err := GetUserDetail(ctx, follow.TargetID)
if err != nil {
return nil, err
}

users = append(users, user)
}

return users, nil
}
func GetUserDetail(ctx context.Context, id int) (*User, error) {
user := &User{}
query := "SELECT id, name, username, bio FROM users WHERE id = ?"
row := sqlDB.QueryRowContext(ctx, query, id)
err := row.Scan(&user.ID, &user.Name, &user.UserName, &user.Bio)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, err
}

return user, nil
}