【问题标题】:Are unused const/function of golang package included in executable binary?golang 包中未使用的 const/function 是否包含在可执行二进制文件中?
【发布时间】:2021-01-04 18:05:14
【问题描述】:

golang包中未使用的const/function/struct方法是否包含在可执行二进制文件中?

例如:

  1. 如果我有一个包Const,其中包含一堆常量(包含SQL 查询),但在main 中使用的常量很少,编译时会全部包含在可执行二进制文件中吗?
package Const
const (
   InsertA = `insert into ...` 
   InsertB = `insert into ...`
   UpdateA1 = `update ...` // certain column
   UpdateA2 = `update ...` // other columns, different where, etc..
   ...
)
// in main, only some of them used/prepared
  1. 如果我有一个包Func,其中包含一堆返回文字(SQL 字符串)的函数,但在main 中只使用了几个函数,编译时是否会全部包含在可执行二进制文件中?
package Func
func InsertA() string { return `insert into ...` }
func InsertB() string { return `insert into ...` }
func UpdateA() string { return `Update ...` }
...
  1. 如果我有一个包mix,其中包含返回/使用所有常量的函数(如数字1),但只有main 中使用的一些函数在编译时会全部包含在可执行二进制文件中吗?
package mix
const (
   insertA = `insert into ...`
   insertB = `insert into ...`
   updateA = `update ...`
   ...
)
func InsertA() string { return insertA }
func InsertB() string { return insertB }
func UpdateA() string { return updateA }
// in main, only some of the const are prepared
  1. 如果我有一个包Struct,其中包含许多带有一堆方法的结构(每个表的分类SQL),但只有main 中调用的一些结构,将所有常量,结构定义,包括的方法编译时在可执行二进制文件中?
package Struct
const (
   insertA = `insert into ...`
   insertB = `insert into ...`
   updateA = `update ...`
   ...
)
// in main only some of them prepared
type A struct {db *DB}
func (a *A) Prepare() error {} 
func (a *A) InsertA(...) error {} 
func (a *A) UpdateA(...) error {} 
type B struct {db *DB}
func (b *B) Prepare() error {} 
func (b *B) InsertB(...) error {} 
// in main only some of them used (eg. only struct `A` used)

上下文/案例用于重构旧代码库,因此它可以更好地调试/理解新程序员的代码(通过合并每个表一个结构或一个包来轻松了解哪些函数/方法修改该表)表)而不牺牲二进制大小,因为目前所有命令查询都分散在多个二进制文件/包中(必须手动 ctrl+F INSERT INTO tablenameUPDATE tablenameDELETE FROM tablename 以查看哪些函数/方法在其上写入/修改记录桌子)。 所以我可以决定是为每个表(250+)一个包更好,还是一个包包含多个包含每个表的空结构的文件。

旧代码库是这样的:

package hugeX
func foo() map[constQ]string {
  return map[constQ]string{
    insertB: `insert into...`,
    updateA: `update ...`,
    ...
  }
}
package hugeY
func foo() map[constQ]string {
  return map[constQ]string{
    insertA: `insert into...`,
    updateB: `update ...`,
    ...
  }
}
package foo
const (
  insertB = `insert into..`
  updateA = `update ...`
  ...
)
package bar // importing hugeX
const ( 
  insertA = `insert into ...` 
  updateA = `update ...` // by something, sometimes duplicates
  ... 
)
package baz 
const (
  ...
)
... and so on..

【问题讨论】:

  • 这是一个内部编译器实现细节,可能因编译器版本和目标而异。不过,关于此代码,您可能仍需要考虑重构。包应该以功能为导向,而不是它们使用的语言结构;永远不应该有包const,或func,或struct。包名也应该全部小写。这段代码将很快变得无法维护,任何其他 Go 开发人员都很难按原样理解它。
  • 在 golang-nuts 邮件列表上有一个关于这个的问题。答案是:链接器只包含被 main 引用的函数,并且包含所有被引用类型的所有方法。
  • 我赞同 Adrian 重构代码的建议。
  • 通常常量不作为单独的实体包含在二进制文件中。它们是不可寻址的常量值,而不是变量。但是,它们的存储方式是一个实施决定。
  • 确实常量根本没有编译到二进制文件中。无论常量名称出现在何处,编译器都会将其替换为常量的值。这就是常量的意义所在。

标签: function go methods struct constants


【解决方案1】:

在测试这些并使用stringsgrep之后

strings binaryName | grep CONSTANTSPREFIX
strings binaryName | grep CONSTANTRETURNEDBYFUNCS
strings binaryName | grep CONSTANTRETURNEDBYMETHODS

类似这样的代码

package a
const (
   A0 = `ZAAA0` // use this on main
   A1 = `ZAAA1`
   A2 = `ZAAA2`
   A3 = `ZAAA3`
   A4 = `ZAAA4`
   A5 = `ZAAA5`
   A6 = `ZAAA6`
)
func B1() string { return A1 } // call this on main
func B2() string { return A2 }
func B3() string { return `ZBBB3` } // call this on main
func B4() string { return `ZBBB4` }
type C1 struct{}
func (c *C1) C3() string { return A3 } // call this on main
func (c *C1) C4() string { return A4 }
type D1 struct{}
func (c *D1) D5() string { return A5 }
func (c *D1) D6() string { return A6 }

主要:

package main
import "a"
import "fmt"
func main() {
        c := a.C1{}
        fmt.Println(a.A0,a.B1(),a.B3(),c.C3())
}

结果

$ go version
go version go1.15.6 linux/amd64
$ go build main.go
$ strings main | grep ZAAA
ZAAA0ZAAA1ZAAA3ZBBB3

只有那些被调用的才会包含在可执行二进制文件中。

【讨论】:

  • 方法和方法引用的常量如果被调用或者工具链不能证明没有通过反射访问该方法包裹。另请注意,工具链折叠常量值。当打印语句更改为fmt.Println(a.A0,a.B1(),a.B3(),c.C3(), "ZAAA0")时,可执行文件中只包含一个ZAAA0
猜你喜欢
  • 2018-06-29
  • 1970-01-01
  • 2013-08-26
  • 2015-07-20
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 2020-01-21
  • 1970-01-01
相关资源
最近更新 更多