在Go开发中,通常会使用类似 var _ core.TweetSearchService = (*bridgeTweetSearchServant)(nil) 的语句借助Go编译器在 编译期 检测某个类型是否完全实现了某个接口的所有方法,比如此例, 如果 *bridgeTweetSearchServant 缺失 接口 core.TweetSearchService 的某些方法实现,Go将会在编译期报错,不能成功编译App.
在工程实践中,可以在 包内 将这类 接口实现约束(Constraint) 语句 统一放在 constraint.go 中,并添加 build tag //go:build constraint 使用tag条件编译机制,只有在使用 go build -tags constraint 时才会进行接口实现约束的检测,在编译产品App时就不带 constraint tag,也就不会把这些 只应在开发期有效的语句 编译到最终的App中。
以下是 『paopao-ce』 的一个使用实例:
// file: https://github.com/rocboss/paopao-ce/blob/dev/internal/dao/search/constraint.go
//go:build constraint
package search
import "github.com/rocboss/paopao-ce/internal/core"
var (
_ core.TweetSearchService = (*bridgeTweetSearchServant)(nil)
_ core.TweetSearchService = (*meiliTweetSearchServant)(nil)
_ core.VersionInfo = (*meiliTweetSearchServant)(nil)
_ core.TweetSearchService = (*zincTweetSearchServant)(nil)
_ core.VersionInfo = (*zincTweetSearchServant)(nil)
)
//go:build constraint 标记 只在 有 -tags constraint 时才进行 接口实现约束 的检测;var _ core.TweetSearchService = (*bridgeTweetSearchServant)(nil) 的语句用于保证某个类型实现了接口定义的所有方法,否则将在编译期间报错;var _ core.TweetSearchService = new(bridgeTweetSearchServant) 这样的语句,更简洁的编写约束语句;// file: https://github.com/rocboss/paopao-ce/blob/dev/internal/core/search.go
// TweetSearchService tweet search service interface
type TweetSearchService interface {
IndexName() string
AddDocuments(data []TsDocItem, primaryKey ...string) (bool, error)
DeleteDocuments(identifiers []string) error
Search(user *ms.User, q *QueryReq, offset, limit int) (*QueryResp, error)
}
// file: https://github.com/rocboss/paopao-ce/blob/dev/internal/dao/bridge.go
type bridgeTweetSearchServant struct {
ts core.TweetSearchService
updateDocsCh chan *documents
updateDocsTempCh chan *documents
}
func (s *bridgeTweetSearchServant) IndexName() string {
return s.ts.IndexName()
}
func (s *bridgeTweetSearchServant) AddDocuments(data []core.TsDocItem, primaryKey ...string) (bool, error) {
s.updateDocs(&documents{
primaryKey: primaryKey,
docItems: data,
})
return true, nil
}
func (s *bridgeTweetSearchServant) DeleteDocuments(identifiers []string) error {
s.updateDocs(&documents{
identifiers: identifiers,
})
return nil
}
func (s *bridgeTweetSearchServant) Search(user *ms.User, q *core.QueryReq, offset, limit int) (*core.QueryResp, error) {
return s.ts.Search(user, q, offset, limit)
}
// ...other logic...

Go:Build Tags 添加 constraint tag,编辑器才会将 //go:build constraint 标记的go文件添加在项目中高亮显示,同时会实时做 接口实现约束 的检测工作,建议在开发环境中正确设置,方便有效的进行项目开发。// file: https://github.com/rocboss/paopao-ce/blob/v0.6.0-alpha.3/internal/dao/search/bridge.go
// 接口实现约束,go在 编译期 检测 `*bridgeTweetSearchServant` 实现了接口 `core.TweetSearchService`
// 如果 检测到缺失某些 接口方法 的实现,将不能成功编译App.
var _ core.TweetSearchService = (*bridgeTweetSearchServant)(nil)
type bridgeTweetSearchServant struct {
ts core.TweetSearchService
updateDocsCh chan *documents
updateDocsTempCh chan *documents
}
func (s *bridgeTweetSearchServant) IndexName() string {
return s.ts.IndexName()
}
func (s *bridgeTweetSearchServant) AddDocuments(data []core.TsDocItem, primaryKey ...string) (bool, error) {
s.updateDocs(&documents{
primaryKey: primaryKey,
docItems: data,
})
return true, nil
}
func (s *bridgeTweetSearchServant) DeleteDocuments(identifiers []string) error {
s.updateDocs(&documents{
identifiers: identifiers,
})
return nil
}
func (s *bridgeTweetSearchServant) Search(user *ms.User, q *core.QueryReq, offset, limit int) (*core.QueryResp, error) {
return s.ts.Search(user, q, offset, limit)
}
// ...other logic...
var _ core.TweetSearchService = (*bridgeTweetSearchServant)(nil),这种方式对App的运行其实没有什么实质影响,可以放心使用。