内联和输出二进制大小

package main

type TreeCell struct {
    Tabs func() *string
}

func Cell() *string {
    s:= ""
    return &s
}

func Table(Line *[]TreeCell) {
    if Line != nil {
        Num["rtt"] = Line
    }
}

var (
    Num map[string]*[]TreeCell 
)

func main() {

    Table(&[]TreeCell{
        TreeCell{Tabs: Cell},
        TreeCell{Tabs: Cell},
        ...repeat 15000 times
        TreeCell{Tabs: Cell},
    })
}

go build -a -v -gcflags "-N -l" -ldflags "-s -w"

Size of executable file 1,9Mb

__text              1459891   16781312
__rodata             158107   18241216
Total               1951521

if I change the func() *string to the interface{}

type TreeCell struct {
    Tabs interface{}
}

then size of executable file 32Mb

__text               1864389   16781312
__rodata            30375699   18645728
Total               32698219

Why?

Go version 1.9.2

The size of an interface{} variable is 8 or 16 bytes (depending on the architecture being 32 or 64 bit), and the size of a function variable is either 4 or 8 bytes. So there is only a 2 multiplication which would not explain the big difference in the output binary (15.000 * 8 bytes is only 120 KB).

What you experience is the result of different inlining compiler optimization. The function Cell() is very simple and is eligible for inlining.

When inlining is disabled

If we include the -gcflags '-N -l' params like in your example (these flags tell the compiler to disable inlining), then references to Cell are not inlined, so using func() *string will only use a 4-byte function pointer.

Using interface{} however will result in inlining Cell values. Interface values hold a copy, and the function call is not inlined, but when the function value is used when implicitly wrapped in interface{} values, it is inlined (duplicated). In each time, that is 15.000 times! So basically the Cell() function body is included 15.000 times. Now that's big, that is what makes the resulting binary 30 MB.

When inlining is enabled

If we exclude the -gcflags '-N -l' params, it's actually the opposite: the compiled binary is about 2 MB when using interface{}, and it's about 30 MB when using func () *string.

This time when using the Cell function value in the composite literal for initializing the TreeCell.Tabs field, the compiler will inline the Cell() function in all 15.000 times! When using interface{}, the function bodies will not be inlined however. Not sure why, a possible explanation is that it is also inlined in case of interface{}, and since interface values are immutable, the same value is used 15.000 times.