Linux supports three types of unix domain socket addresses. pathname, unnamed and abstract. abstract socket address is very convenient but there’s a pitfall of using it in Go.

If you want to use an abstract socket address, its name should starts with ‘@’, not ‘\0’.

net.UnixAddr{"@myname", "unix"} // address is {'\0','m','y','n','a','m','e' }

If address name starts with ‘@’, Go converts ‘@’ to ‘\0’ and do not append ‘\0’ at the end of the string.

If address name starts with ‘\0’, the resulting address may not be what you want.

net.UnixAddr{"\x00myname", "unix"} // address is {'\0','m','y','n','a','m','e','\0'}

There are three types of unix domain socket.

  1. "unix" corresponds to SOCK_STREAM
  2. "unixdomain" corresponds to SOCK_DGRAM
  3. "unixpacket" corresponds to SOCK_SEQPACKET

When you write a “unix” or “unixpacket” server, use ListenUnix().

 l, err := net.ListenUnix("unix",  &net.UnixAddr{"/tmp/unixdomain", "unix"})
if err != nil {
    panic(err)
}   
defer os.Remove("/tmp/unixdomain")

for {
    conn, err := l.AcceptUnix()
    if err != nil {
        panic(err)
    }
    var buf [1024]byte
    n, err := conn.Read(buf[:])
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s\n", string(buf[:n]));
    conn.Close()
}   

"unixgram" server uses ListenUnixgram().

conn, err := net.ListenUnixgram("unixgram",  &net.UnixAddr{"/tmp/unixdomain", "unixgram"})
if err != nil {
    panic(err)
}   
defer os.Remove("/tmp/unixdomain")

for {
    var buf [1024]byte
    n, err := conn.Read(buf[:])
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s\n", string(buf[:n]));
}   

Client is as follows

type := "unix" // or "unixgram" or "unixpacket"
laddr := net.UnixAddr{"/tmp/unixdomaincli", type}
conn, err := net.DialUnix(type, &laddr/*can be nil*/, 
    &net.UnixAddr{"/tmp/unixdomain", type})
if err != nil {
    panic(err)
}   
defer os.Remove("/tmp/unixdomaincli")

_, err = conn.Write([]byte("hello"))
if err != nil {
    panic(err)
}   
conn.Close()

Do you know what exactly associated template is? It’s one of the concepts that confused me a lot. This post explains what associated template is in detail.

I’ll use a term “template group” in order to explain what associated template is. The term is not in the official godoc.

template.New()

When you create a template with template.New(),

t1 := template.New("t1")

a template object is created with the name specified. At the same time, a template group is created.

A template group is a object with a FuncMap and a list of Template that the group has. (The list is implemented as a map internally, but it’s shown as a list for brevity)

At this point, t1 is not in the template list yet. When you call Parse(),

t1.Parse(...)

"t1" is added to the template list.

Associate a template with t.New()

When you call the following,

t2, err := t1.New("t2").Parse(...)
t3, err := t1.New("t3").Parse(...)

it creates the following structure.

t1, t2 and t3 are all members of the same group. They share FuncMap and the template list.

Godoc of t.New(name string) says.

New allocates a new template associated with the given one 
and with the same delimiters. The association, which is transitive, 
allows one template to invoke another with a {{template}} action.

It’s easy to understand what the godoc means with the above diagram. When templates are associated, they are in the same group.

Name of a Template

Each template has a name. It’s not allowed to add more than one templates to the template list by calling Parse().

Template name need to be unique in a group. It’s OK to have templates with the same name if they belong to different groups.

tA,err := template.New("t1").Parse(...)
tB,err := template.New("t1").Parse(...)

t.Lookup()

t.Lookup(name string) finds the template by name in a group.

You can use any receiver objects to find a template. Following three codes return the same template object.

t1.Lookup("t3") // returns t3
t2.Lookup("t3") // returns t3
t3.Lookup("t3") // returns t3

t.Templates()

t.Templates() returns a copy of the list of templates in the group.

All of the following codes return lists with the same contents.

t1.Templates()
t2.Templates()
t3.Templates()

Difference between t.Execute() and t.ExecuteTemplate()

t.Execute() uses the template t itself.

t1.Execute(w, obj)

t.ExecuteTemplate() looks up a template by name, and execute the looked-up template.

t1.ExecuteTemplate(w, "t3", obj)

Following three codes are equivalent.

t1.ExecuteTemplate(w, "t3", obj) // = t3.Execute(w, obj)
t2.ExecuteTemplate(w, "t3", obj) // = t3.Execute(w, obj)
t3.ExecuteTemplate(w, "t3", obj) // = t3.Execute(w, obj)

What template.ParseFiles() does

template.ParseFiles() creates templates and put all of them in a same group.

t, err := template.ParseFiles("a/go.tmpl", "b/lang.tmpl", "c/rocks.tmpl")

creates following structure.

Name of each templates is a base name of the file.

The returned template is the first template created. In the above code, the template with the name “go.tmpl” is returned.

Add HTTP header with SetBasicAuth().

req, err := http.NewRequest("GET", url, nil)
req.SetBasicAuth(user, pass)
cli := &http.Client{}
resp, err := cli.Do(req)

There’s no API for digest authentication in standard library.

It’s a reverse dictionary of printing format of fmt package. It let you find the right verbs from desired output quickly.

General

the value in a default format %v
type of the value %T

Integer

+255 Always show sign %+d
'ÿ' Single quoted %q
377 Octal without leading ‘0’ %o
0377 Octal with leading ‘0’ %#o
ff Hex lowercase %x
FF Hex uppercase %X
0xff Hex with “0x” %#x
U+00FF Unicode %U
U+00FF ‘ÿ’ Unicode with char %#U
11111111 Binary %b

Integer width

|    1|
|   12|
|  123|
| 1234|
|12345|
|123456|
|1234567|
|1    |
|12   |
|123  |
|1234 |
|12345|
|123456|
|1234567|
Minimum width=5. Expand if wider. %5d
%-5d (Left justify)
|    1|
|   12|
|  123|
| 1234|
|12345|
|12345|
|12345|
|1    |
|12   |
|123  |
|1234 |
|12345|
|12345|
|12345|
Width=5. Truncate right if wider. fmt.Printf(“%s”, fmt.Sprintf(“%5d”, value)[:5]))
fmt.Printf(“%s”, fmt.Sprintf(“%-5d”, value)[:5])) (Left justify)
  or
fmt.Printf(“|%5.5s|\n”, strconv.Itoa(value))
fmt.Printf(“|%-5.5s|\n”, strconv.Itoa(value)) (Left justify)
|    1|
|   12|
|  123|
| 1234|
|12345|
|23456|
|34567|
|1    |
|12   |
|123  |
|1234 |
|12345|
|23456|
|34567|
Width=5. Truncate left if wider. fmt.Printf(“%5d”, val % 100000)
fmt.Printf(“%-5d”, val % 100000) (Left justify)
|0012345| Pad with ‘0’ (Right justify only) %07d

Float

original %f (=%.6f)
6 digits after decimal
%e (=%.6e)
6 digits after decimal
%g
smallest number of digits necessary
%.3g
total number of digits=3
12345
1234.5
123.45
12.345
1.2345
0.12345
0.012345
0.0012345
0.00012345
0.000012345
0.0000012345
12345.000000
1234.500000
123.450000
12.345000
1.234500
0.123450
0.012345
0.001234
0.000123
0.000012
0.000001
1.234500e+04
1.234500e+03
1.234500e+02
1.234500e+01
1.234500e+00
1.234500e-01
1.234500e-02
1.234500e-03
1.234500e-04
1.234500e-05
1.234500e-06
12345
1234.5
123.45
12.345
1.2345
0.12345
0.012345
0.0012345
0.00012345
1.2345e-05
1.2345e-06
1.23e+04
1.23e+03
123
12.3
1.23
0.123
0.0123
0.00123
0.000123
1.23e-05
1.23e-06

String

love is "愛" Normal %s
"love is \"愛\"" Double-quoted %q
`love is "愛"` Back-quoted if possible. Otherwise, double-quoted %#q
"love is \"\u611b\"" Double-quoted. ASCII only. %+q
6c6f76652069732022e6849b22 Hex lowercase. %x
6C6F76652069732022E6849B22 Hex uppercase. %X
6c 6f 76 65 20 69 73 20 22 e6 84 9b 22 Hex with space. % x

String width

|    1|
|   12|
|  123|
| 1234|
|12345|
|123456|
|1234567|
|12345678|
|123456789|
|1234567890|
|1    |
|12   |
|123  |
|1234 |
|12345|
|123456|
|1234567|
|12345678|
|123456789|
|1234567890|
Minimum width=5. Expand if wider. %5s
%-5s (Left justify)
|1|
|12|
|123|
|1234|
|12345|
|12345|
|12345|
Maximum width=5(Expand up to 5). %.5s
|    1|
|   12|
|  123|
| 1234|
|12345|
|123456|
|1234567|
|1234567|
|1234567|
|1234567|
|1    |
|12   |
|123  |
|1234 |
|12345|
|123456|
|1234567|
|1234567|
|1234567|
|1234567|
Minimum width=5. Expand up to 7. %5.7s
%-5.7 (Left justify)
|    1|
|   12|
|  123|
| 1234|
|12345|
|12345|
|12345|
|1    |
|12   |
|123  |
|1234 |
|12345|
|12345|
|12345|
Width=5. %5.5s
%-5.5s (Left justify)
|    1|
|   12|
|  123|
|  123|
|  123|
|1    |
|12   |
|123  |
|123  |
|123  |
Width=5. Truncate if wider than 3. %5.3s
%-5.3s (Left justify)
|0012345| |12345  | Pad with ‘0’. Doen’t work when left-justify %07s

Struct

{sam {12345 67890}} Normal %v
{name:sam phone:{mobile:12345 office:67890} With field names %+v
main.People{name:”sam”, phone:main.Phone{mobile:”12345”, office:”67890”}} Go’s syntax %#v

Boolean

true
false
Boolean %t

Pointer

0x1842c220 Pointer with 0x %p
1842c220 Pointer without 0x %#p

Float32bits() is available in math package. It returns IEEE754 binary representation of a float value.

f := float32(1)
fmt.Printf("%x\n", math.Float32bits(f)) // Prints "3f800000"

The implementation of the function is very simple. Just one line.

func Float32bits(f float32) uint32 { 
    return *(*uint32)(unsafe.Pointer(&f)) 
}

I’m glad that Go provides these kinds of simple and useful functions. They reduce the complexity of my code a lot.

When you convert []byte to string, Go allocates new memory for the string and copies contents.

a := []byte{'1','2','3','4','5'}
b := string(a)

a[0] = 'a' 

fmt.Printf("%s\n", a)
fmt.Printf("%s\n", b)

It prints,

a2345
12345

a and b don’t share any memory. The same rule applies when you convert string to []byte too.

Even in following code, e and f don’t share memory.

e := []byte{1,2,3,4,5}
f := []byte(string(e)) // convert to string and convert back to []byte

e[0] = 0x30

When you make a conversion between []byte and string, it calls following functions internally.

  • runtime.stringtoslicebyte()
  • runtime.slicebytetostring()

Those functions are defined in src/pkg/runtime/string.goc (A .goc file is a combination of a limited form of Go with C). You can easily see they copy the memory contents.

func slicebytetostring(b Slice) (s String) {
    void *pc;

    if(raceenabled) {
        pc = runtime·getcallerpc(&b);
        runtime·racereadrangepc(b.array, b.len, pc, runtime·slicebytetostring);
    }   
    s = gostringsize(b.len);
    runtime·memmove(s.str, b.array, s.len);
}

func stringtoslicebyte(s String) (b Slice) {
    b.array = runtime·mallocgc(s.len, 0, FlagNoScan|FlagNoZero);
    b.len = s.len;
    b.cap = s.len;
    runtime·memmove(b.array, s.str, s.len);
}

In short, bytes.Buffer is the fastest way to concatenate strings. append([]byte, string) is not bad.

I compared following three ways to concatenate strings.

A. simple string concatenation

for i := 0; i < b.N; i++ {
    s1 = s1 + s2
}   

B. byte slice appending

s3 := []byte(s1)
for i := 0; i < b.N; i++ {
    s3 = append(s3, s2...)
}   
s1 = string(s3)

C. bytes.Buffer

var buffer bytes.Buffer
for i := 0; i < b.N; i++ {
    buffer.WriteString(s2)
}
s1 := buffer.String()

Below is the benchmark result.

BenchmarkStringAppend      20000         32787 ns/op
BenchmarkSliceAppend     5000000            65.2 ns/op
BenchmarkByteBufferAppend   20000000            49.6 ns/op

Simple string concatenation is very slow if you need to concatenate a lot of strings. Slice appending is much faster than simple concatenation. bytes.Buffer is slightly faster than slice appending.

Do you know the difference between following two functions?

func showMd1(b []byte) {
    hash := md5.New()
    md := hash.Sum(b)
    fmt.Printf("%s\n", hex.EncodeToString(md))
}

func showMd2(b []byte) {
    md := md5.Sum(b)
    fmt.Printf("%s\n", hex.EncodeToString(md[:]))
}

The former appends md5 hash to b. Below is what they prints.

showMd1([]byte{ 1, 2, 3, 4, 5, 6 })
-> 010203040506d41d8cd98f00b204e9800998ecf8427e
Hash of empty byte array is appended to 1,2,3,4,5,6.

showMd2([]byte{ 1, 2, 3, 4, 5, 6 })
-> 6ac1e56bc78f031059be7be854522c4c
Hash of []byte{1,2,3,4,5,6}

It’s pretty confusing. hash.Sum() is not the same as final() or digest() in other platforms. In most cases, you should not pass a slice to hash.Sum(). Pass nil to hash.Sum() just like,

    hash := md5.New()
    hash.Write(b)
    md := hash.Sum(nil)

Go’s regexp package has 16 variants of Find*() methods. I’m always confused about which method I should use. Use following cheatsheet to find the right method quickly.


4 methods that return strings. Methods returning strings


4 methods that return indexes. Methods returning indexex


If you need to match against []byte, use methods without “String” like “Find” or “FindAllSubmatch”.

Use os.TempDir() to get the name of the directory and ioutil.TempFile() to create a file.

file, err := ioutil.TempFile(os.TempDir(), "prefix")
defer os.Remove(file.Name())

It’s caller’s responsibility to remove the file.

Use runtime/pprof package

func main() {
    if (useProfile) {
        f, err := os.Create("proffilename.prof")
        if err != nil {
            panic(err)
        }
        pprof.StartCPUProfile(f)
        defer pprof.StopCPUProfile()
    }
    ...

Run ‘go tool pprof’ to analyze prof file.

$ go tool pprof <APPNAME> <PROFILENAME>
Welcome to pprof!  For help, type 'help'.
(pprof) top10

See Go blog for more detail.

Use os.OpenFile()

f, err := os.OpenFile(filename, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0777)
if err != nil {
    panic(err)
}

If you want to open a file just for reading, os.Open() is easier to use.

f, err := os.Open(filename)
if err != nil {
    panic(err)
}

bio.ReadBytes() is more convenient than bio.ReadLine().

bio := bufio.NewReader(os.Stdin)
for {
    line, err := bio.ReadBytes('\n')
    if err == io.EOF {
        break
    }
    if err != nil {
        panic(err)
    }
    sline := strings.TrimRight(string(line), "\n")
    ...
}

Use sort.Sort(data Interface). data is an object that is not necessarily a slice. data need to implement following functions.

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

If you want to sort []int, define a type intArray

type intArray []int
func (s intArray) Len() int { return len(s) }
func (s intArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s intArray) Less(i, j int) bool { return s[i] < s[j] }

and cast []int to intArray.

a := []int {1,5,10,4}
sort.Sort(intArray(a))