GOLANG 编译期的`常量折叠`的研究 发现了奇怪的代码func (m *Child) SizeVT() (n int) { if m nil { return 0 } var l int _ l if m.ChildId ! 0 { n 1 protohelpers.SizeOfVarint(uint64(m.ChildId)) } l len(m.ChildName) if l 0 { n 1 l protohelpers.SizeOfVarint(uint64(l)) } return n }这个函数的作用是计算一个类型序列化后要占多大的空间。其中可以发现两个常量值 1.我再翻翻我自己的实现我是这样写的func (m *Child) ProtobufSize() int { size : 0 if m.ChildName ! { n : len(m.ChildName) size TagSize(ChildChildNameTag, LenDelim) utils.VarintSize(uint64(n)) n } if m.ChildID ! 0 { size TagSize(ChildChildIDTag, Varint) utils.VarintSize(uint64(m.ChildID)) } return size }原来这个 1 是 tagID 数据类型编码后占 1 字节。难怪他的库更快他相当于做了“编译期计算”提前得到了函数运算的结果。我好奇的是如果函数的参数都是常量为什么编译器没有为我计算好我收集了如下知识编译器常量折叠通常受哪些因素影响条件 1函数是否能内联函数很小能被内联func A(a byte, b byte) byte { return (a 0x0f) | (b 0xf0) }如果函数太复杂不能内联编译器一般不会跨函数直接求值。func A(a byte, b byte) byte { for i : 0; i 10; i { a ^ byte(i) } return (a 0x0f) | (b 0xf0) }函数如果没有被内联调用点就不会被折叠成常量。条件 2实参是否是编译期已知值可以折叠的情况func A(a byte, b byte) byte{ return (a0x0f) | (b0xf0) } a : A(0x1f, 0x2f)不能折叠x : byte(time.Now().Unix()) a : A(x, 0x2f)畅享希望golang 提供的编译期计算能力const 的值可以调用一个函数来得到const name function_call(123)constexpr 关键字constexpr func A(...){} a : A(12345) // 对于 constexpr 函数都尽可能在编译期完成计算