2022-05-25
Go语言
00
请注意,本文编写于 847 天前,最后修改于 584 天前,其中某些信息可能已经过时。

目录

打造自己的Go语言工具集
1. 单词格式转换
1.1 安装和初始化目录结构
1.2 单词转换逻辑
1.2.1 大小写转换
1.2.2 下划线转大写驼峰
1.2.3 下划线转小写驼峰
1.2.4 驼峰转下划线
1.3 集成word命令并验证
1.3.1 cmd/word.go
1.3.2 cmd/root.go
1.3.3 验证
2. 时间工具
2.1 目录结构
2.2 集成子命令并验证
2.2.1 internal/timer/time.go
2.2.2 cmd/time.go
2.2.3 cmd/root.go
2.2.4 验证
2.3 时区问题
2.4 关于 2006-01-02 15:04:05
3. SQL语句到结构体的转换
3.1 目录结构
3.2 集成子命令并验证
3.2.1 internal/sql2struct/mysql.go
3.2.2 internal/sql2struct/template.go
3.2.3 cmd/sql.go
3.2.4 cmd/root.go
3.2.5 验证
4. JSON到结构体的转换
4.1 目录结构
4.2 集成子命令并验证
3.2.1 internal/json2struct/parser.go
3.2.2 internal/json2struct/fields.go
3.2.3 cmd/json.go
4.2.4 cmd/root.go
4.2.5 验证
5. 最终目录结构

打造自己的Go语言工具集

内容来源于《Go语言编程之旅》

1. 单词格式转换

手动修改字符串的命名格式太累且效率太低,不如写个自动化小工具吧

1.1 安装和初始化目录结构

  • 首先需要安装本项目所依赖的基础库 Cobra
shell
go get -u github.com/spf13/cobra@v1.0.0
  • 目录结构
│ go.mod │ go.sum │ main.go │ ├─cmd │ root.go 根命令 │ word.go 用于单词格式转换的子命令 word 的设置 │ ├─internal │ └─word │ word.go 具体的功能代码 │ └─pkg

1.2 单词转换逻辑

常见的字符串命名格式共五种,转换也限于这五种的转换

  • 单词全部转为小写
  • 单词全部转为大写
  • 下划线单词转为大写驼峰
  • 下划线单词转为小写驼峰
  • 驼峰转为小写驼峰

相关的功能代码写入internal\word\word.go

├─internal │ └─word │ word.go 具体的功能代码

1.2.1 大小写转换

go
// 大小写转换 func ToUpper(s string) string { return strings.ToUpper(s) } func ToLower(s string) string { return strings.ToLower(s) }

1.2.2 下划线转大写驼峰

go
// 下划线转大写驼峰 func UnderscoreToUpperCamelCase(s string) string { s = strings.Replace(s, "_", " ", -1) // 先将下划线替换为空格 s = strings.Title(s) // 将所有字符修改为对应的首字母大写格式 return strings.Replace(s, " ", "", -1) // 将空格去掉并返回 }

1.2.3 下划线转小写驼峰

go
// 下划线转小写驼峰 func UnderscoreToLowerCamelCase(s string) string { s = UnderscoreToUpperCamelCase(s) // 先转换为大写驼峰 return string(unicode.ToLower((rune(s[0])))) + s[1:] // 将第一个字母修改为小写 }

1.2.4 驼峰转下划线

go
// 驼峰转下划线 func CamelCaseToUnderscore(s string) string { var output []rune for i, r := range s { if i == 0 { // 如果是第一个字母,变为小写并继续遍历 output = append(output, unicode.ToLower(r)) continue } if unicode.IsUpper(r) { // 遇到大写字母,说明遇到驼峰,需要加入下划线 output = append(output, '_') } output = append(output, unicode.ToLower(r)) // 将大写字母变为小写 } return string(output) // 转换为string并返回 }

1.3 集成word命令并验证

将上述方法集成到Command中

相关的功能代码写入cmd\word.gocmd\root.go

├─cmd │ root.go 根命令 │ word.go 用于单词格式转换的子命令 word 的设置

1.3.1 cmd/word.go

go
const ( ModeUpper = iota + 1 // 全部转大写,分别为1,2,3,4,5 ModeLower // 全部转小写 ModeUnderscoreToUpperCamelCase // 下划线转大写驼峰 ModeUnderscoreToLowerCamelCase // 下划线转小写驼峰 ModeCamelCaseToUnderscore // 驼峰转下划线 ) var desc = strings.Join([]string{ // 命令提示语句 "该子命令支持各种单词格式转换,模式如下:", "1:全部转大写", "2:全部转小写", "3:下划线转大写驼峰", "4:下划线转小写驼峰", "5:驼峰转下划线", }, "\n") var str string var mode int8 var wordCmd = &cobra.Command{ // word命令 Use: "word", // 子命令的命令标识 Short: "单词格式转换", // 子命令的简短说明 Long: desc, // 子命令的完整说明 Run: func(cmd *cobra.Command, args []string) { // 命令的逻辑 var content string switch mode { // 根据不同的模式,选择对应的功能代码 case ModeUpper: content = word.ToUpper(str) case ModeLower: content = word.ToLower(str) case ModeUnderscoreToUpperCamelCase: content = word.UnderscoreToUpperCamelCase(str) case ModeUnderscoreToLowerCamelCase: content = word.UnderscoreToLowerCamelCase(str) case ModeCamelCaseToUnderscore: content = word.CamelCaseToUnderscore(str) default: log.Fatalf("暂不支持该转换模式,请执行 help word 查看帮助文档") } log.Printf("输出结果: %s", content) }, } func init() { // 获取命令行参数,给str和mode赋值 wordCmd.Flags().StringVarP(&str, "str", "s", "", "请输入单词内容") wordCmd.Flags().Int8VarP(&mode, "mode", "m", 0, "请输入单词转换的模式") }

1.3.2 cmd/root.go

go
var rootCmd = &cobra.Command{} func Execute() error { // 执行 return rootCmd.Execute() } func init() { rootCmd.AddCommand(wordCmd) // 注册wordCmd }

1.3.3 验证

shell
go run main.go help word 该子命令支持各种单词格式转换,模式如下: 2:全部转小写 3:下划线转大写驼峰 4:下划线转小写驼峰 5:驼峰转下划线 Usage: word [flags] Flags: -m, --mode int8 请输入单词转换的模式 -s, --str string 请输入单词内容 go run main.go word -s=southyang -m=1 输出结果: SOUTHYANG go run main.go word -s=south_yang -m=2 输出结果: south_yang go run main.go word -s=south_yang -m=3 输出结果: SouthYang go run main.go word -s=south_yang -m=4 输出结果: southYang go run main.go word -s=SouthYang -m=5 输出结果: south_yang

2. 时间工具

2.1 目录结构

├─cmd │ root.go │ time.go 时间工具子命令 time 的设置 │ word.go │ ├─internal │ ├─timer │ │ time.go 时间工具的逻辑代码 │ │ │ └─word │ word.go

2.2 集成子命令并验证

2.2.1 internal/timer/time.go

go
func GetNowTime() time.Time { // 获取当前时间 location, _ := time.LoadLocation("Asia/Shanghai") // 设置时区 return time.Now().In(location) } func GetCalculateTime(currentTimer time.Time, d string) (time.Time, error) { // 时间推算 duration, err := time.ParseDuration(d) if err != nil { return time.Time{}, err } return currentTimer.Add(duration), nil }

2.2.2 cmd/time.go

go
var descTime = strings.Join([]string{ "该命令的子命令支持各种时间工具", "now:获取当前时间", "calc:计算所需时间", }, "\n") var calculateTime string var duration string // 定义两种时间格式 const TimeLayout = "2006-01-02" const TimeLayout1 = "2006-01-02 15:04:05" const LocationTime = "Asia/Shanghai" var timeCmd = &cobra.Command{ Use: "time", Short: "时间格式处理", Long: descTime, Run: func(cmd *cobra.Command, args []string) {}, } var nowTimeCmd = &cobra.Command{ // 输出两种时间格式 Use: "now", Short: "获取当前时间", Long: "获取当前时间", Run: func(cmd *cobra.Command, args []string) { nowTime := timer.GetNowTime() log.Printf("输出结果: %s, %d", nowTime.Format("2006-01-02 15:04:05"), nowTime.Unix()) }, } var calculateTimeCmd = &cobra.Command{ Use: "calc", Short: "计算所需时间", Long: "计算所需时间", Run: func(cmd *cobra.Command, args []string) { var currentTimer time.Time location, _ := time.LoadLocation(LocationTime) var layout = "2006-01-02 15:04:05" if calculateTime == "" { currentTimer = timer.GetNowTime() } else { var err error space := strings.Count(calculateTime, " ") if space == 0 { // 判断时间格式 layout = TimeLayout } if space == 1 { layout = TimeLayout1 } currentTimer, err = time.ParseInLocation(layout, calculateTime, location) if err != nil { // 如果出现错误,则按照时间戳的格式处理 t, _ := strconv.Atoi(calculateTime) currentTimer = time.Unix(int64(t), 0) } } t, err := timer.GetCalculateTime(currentTimer, duration) if err != nil { log.Fatalf("timer.GetCalculateTime err: %v", err) } log.Printf("输出结果: %s, %d", t.Format(layout), t.Unix()) }, } func init() { timeCmd.AddCommand(nowTimeCmd) // 注册两个子命令 timeCmd.AddCommand(calculateTimeCmd) // 获取命令行参数,给calculate,duration赋值 calculateTimeCmd.Flags().StringVarP(&calculateTime, "calculate", "c", "", ` 需要计算的时间,有效单位为时间戳或已格式化后的时间 `) calculateTimeCmd.Flags().StringVarP(&duration, "duration", "d", "", ` 持续时间,有效时间单位为"ns", "us" (or "µ s"), "ms", "s", "m", "h"`) }

2.2.3 cmd/root.go

在根命令中注册time子命令

go
var rootCmd = &cobra.Command{} func Execute() error { return rootCmd.Execute() } func init() { rootCmd.AddCommand(wordCmd) rootCmd.AddCommand(timeCmd) // 新增 }

2.2.4 验证

shell
go run .\main.go help time 该命令的子命令支持各种时间工具 now:获取当前时间 calc:计算所需时间 Usage: time [command] Available Commands: now 获取当前时间 Flags: -h, --help help for time Use " time [command] --help" for more information about a command. go run main.go time now 输出结果: 2022-05-20 12:04:05, 1653019445 go run main.go time calc -c="2029-09-04 12:02:33" -d=-2h 输出结果: 2029-09-04 10:02:33, 1883210553

2.3 时区问题

代码运行的环境不一样,可能会根据时区的不同出现各种问题

我们可以根据名称获取特定时区的 Location 实例

go
location, _ := time.LoadLocation("Asia/Shanghai")

对于Parse()方法,该方法会尝试在入参的参数中中分析并读取时区信息,但是如果入参的参数没有指定时区信息的话,那么就会默认使用 UTC 时间

我们可以使用ParseInLocation()避免这个问题

go
t, _ := time.ParseInLocation(layout, inputTime, location) dateTime := time.Unix(t.Unix(), 0).In(location).Format(layout)

2.4 关于 2006-01-02 15:04:05

官方的例子如下

Jan 2 15:04:05 2006 MST 1 2 3 4 5 6 -7

我们可以将2006-01-02 15:04:05记忆为2006 年 1 月 2 日 3 点 4 分 5 秒

3. SQL语句到结构体的转换

当我们添加新的数据表时,有时候需要添加模型结构,也就是需要我们写Model结构体,如果是手写效率太低了

我们可以通过自己实现小工具来实现数据库表到Go结构体的转换

(如果是云数据库应该会支持建表语句导出,应该有类似的转换工具可以找一找)

3.1 目录结构

├─cmd 子命令集 │ root.go 根命令 │ sql.go sql struct : sql转结构体 │ time.go time now/calc : 求当前时间和所需要的时间 │ word.go word : 字符串格式转换 ├─internal 逻辑函数 │ ├─sql2struct │ │ mysql.go │ │ template.go

3.2 集成子命令并验证

3.2.1 internal/sql2struct/mysql.go

go
type DBModel struct { DBEngine *sql.DB DBInfo *DBInfo } type DBInfo struct { DBType string Host string UserName string Password string Charset string } type TableColumn struct { ColumnName string DataType string IsNullable string ColumnKey string ColumnType string ColumnComment string } var DBTypeToStructType = map[string]string{ "int": "int32", "tinyint": "int8", "smallint": "int", "mediumint": "int64", "bigint": "int64", "bit": "int", "bool": "bool", "enum": "string", "set": "string", "varchar": "string", "char": "string", "tinytext": "string", "mediumtext": "string", "text": "string", "longtext": "string", "blob": "string", "tinyblob": "string", "mediumblob": "string", "longblob": "string", "date": "time.Time", "datetime": "time.Time", "timestamp": "time.Time", "time": "time.Time", "float": "float64", "double": "float64", } func NewDBModel(info *DBInfo) *DBModel { return &DBModel{DBInfo: info} } func (m *DBModel) Connect() error { var err error s := "%s:%s@tcp(%s)/information_schema?" + "charset=%s&parseTime=True&loc=Local" dsn := fmt.Sprintf( s, m.DBInfo.UserName, m.DBInfo.Password, m.DBInfo.Host, m.DBInfo.Charset, ) m.DBEngine, err = sql.Open(m.DBInfo.DBType, dsn) if err != nil { return err } return nil } func (m *DBModel) GetColumns(dbName, tableName string) ([]*TableColumn, error) { query := "SELECT COLUMN_NAME, DATA_TYPE, COLUMN_KEY, " + "IS_NULLABLE, COLUMN_TYPE, COLUMN_COMMENT " + "FROM COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? " rows, err := m.DBEngine.Query(query, dbName, tableName) if err != nil { return nil, err } if rows == nil { return nil, errors.New("没有数据") } defer rows.Close() var columns []*TableColumn for rows.Next() { var column TableColumn err := rows.Scan(&column.ColumnName, &column.DataType, &column.ColumnKey, &column.IsNullable, &column.ColumnType, &column.ColumnComment) if err != nil { return nil, err } columns = append(columns, &column) } return columns, nil }

3.2.2 internal/sql2struct/template.go

go
const strcutTpl = `type {{.TableName | ToCamelCase}} struct { {{range .Columns}} {{ $length := len .Comment}} {{ if gt $length 0 }}// {{.Comment}} {{else}}// {{.Name}} {{ end }} {{ $typeLen := len .Type }} {{ if gt $typeLen 0 }}{{.Name | ToCamelCase}} {{.Type}} {{.Tag}}{{ else }}{{.Name}}{{ end }} {{end}}} func (model {{.TableName | ToCamelCase}}) TableName() string { return "{{.TableName}}" }` type StructTemplate struct { strcutTpl string } type StructColumn struct { Name string Type string Tag string Comment string } type StructTemplateDB struct { TableName string Columns []*StructColumn } func NewStructTemplate() *StructTemplate { return &StructTemplate{strcutTpl: strcutTpl} } func (t *StructTemplate) AssemblyColumns(tbColumns []*TableColumn) []*StructColumn { tplColumns := make([]*StructColumn, 0, len(tbColumns)) for _, column := range tbColumns { tag := fmt.Sprintf("`"+"json:"+"\"%s\""+"`", column.ColumnName) tplColumns = append(tplColumns, &StructColumn{ Name: column.ColumnName, Type: DBTypeToStructType[column.DataType], Tag: tag, Comment: column.ColumnComment, }) } return tplColumns } func (t *StructTemplate) Generate(tableName string, tplColumns []*StructColumn) error { tpl := template.Must(template.New("sql2struct").Funcs(template.FuncMap{ "ToCamelCase": word.UnderscoreToUpperCamelCase, }).Parse(t.strcutTpl)) tplDB := StructTemplateDB{ TableName: tableName, Columns: tplColumns, } err := tpl.Execute(os.Stdout, tplDB) if err != nil { return err } return nil }

3.2.3 cmd/sql.go

go
var username string var password string var host string var charset string var dbType string var dbName string var tableName string var sqlCmd = &cobra.Command{ Use: "sql", Short: "sql转换和处理", Long: "sql转换和处理", Run: func(cmd *cobra.Command, args []string) {}, } var sql2structCmd = &cobra.Command{ Use: "struct", Short: "sql转换", Long: "sql转换", Run: func(cmd *cobra.Command, args []string) { dbInfo := &sql2struct.DBInfo{ DBType: dbType, Host: host, UserName: username, Password: password, Charset: charset, } dbModel := sql2struct.NewDBModel(dbInfo) err := dbModel.Connect() if err != nil { log.Fatalf("dbModel.Connect err: %v", err) } columns, err := dbModel.GetColumns(dbName, tableName) if err != nil { log.Fatalf("dbModel.GetColumns err: %v", err) } template := sql2struct.NewStructTemplate() templateColumns := template.AssemblyColumns(columns) err = template.Generate(tableName, templateColumns) if err != nil { log.Fatalf("template.Generate err: %v", err) } }, } func init() { sqlCmd.AddCommand(sql2structCmd) sql2structCmd.Flags().StringVarP(&username, "username", "", "", "请输入数据库的账号") sql2structCmd.Flags().StringVarP(&password, "password", "", "", "请输入数据库的密码") sql2structCmd.Flags().StringVarP(&host, "host", "", "", "请输入数据库的HOST") sql2structCmd.Flags().StringVarP(&charset, "charset", "", "utf8mb4", "请输入数据库的编码") sql2structCmd.Flags().StringVarP(&dbType, "type", "", "mysql", "请输入数据库实例类型") sql2structCmd.Flags().StringVarP(&dbName, "db", "", "", "请输入数据库名称") sql2structCmd.Flags().StringVarP(&tableName, "table", "", "", "请输入表名称") }

3.2.4 cmd/root.go

go
var rootCmd = &cobra.Command{} func Execute() error { return rootCmd.Execute() } func init() { rootCmd.AddCommand(wordCmd) rootCmd.AddCommand(timeCmd) rootCmd.AddCommand(sqlCmd) }

3.2.5 验证

go run main.go sql struct --username 用户名 --password 密码 --host 主机地址 --db 数据库名 --table 数据表名 type GoUser struct { Phone string `json:"phone"` // uid Uid int64 `json:"uid"` // username Username string `json:"username"` } func (model GoUser) TableName() string { return "go_user" }

4. JSON到结构体的转换

有时候我们在写代码的时候会遇到极为庞大的json数据,而如果我们要对其中的数据做出修改,就必须建立对应的结构体

在我写Go语言项目(CSUAPI)的时候就遇到了这个问题,庞大的图书馆座位数据需要处理,但结构体太复杂,指望我手动写结构体效率太低且无意义,所以我,一股脑全发给前端了hh

如果要优化那个项目的话,我想这次我可以用这个小工具来构建结构体,从而对数据做一些处理了

4.1 目录结构

├─cmd 子命令集 │ json.go json struct : json转结构体 │ root.go 根命令 │ sql.go sql struct : sql转结构体 │ time.go time now/calc : 求当前时间和所需要的时间 │ word.go word : 字符串格式转换 ├─internal 逻辑函数 │ ├─json2struct │ │ fields.go │ │ parser.go

4.2 集成子命令并验证

3.2.1 internal/json2struct/parser.go

go
const ( TYPE_MAP_STRING_INTERFACE = "map[string]interface {}" TYPE_INTERFACE = "[]interface {}" ) type Parser struct { Source map[string]interface{} Output Output Children Output StructTag string StructName string } type Output []string func (o *Output) appendSegment(format, title string, args ...interface{}) { s := []interface{}{} s = append(s, word.UnderscoreToUpperCamelCase(title)) if len(args) != 0 { s = append(s, args...) format = " " + format } *o = append(*o, fmt.Sprintf(format, s...)) } func (o *Output) appendSuffix() { *o = append(*o, "}\n") } func NewParser(s string) (*Parser, error) { var source map[string]interface{} err := json.Unmarshal([]byte(s), &source) if err != nil { return nil, err } return &Parser{ Source: source, StructTag: "type %s struct {", StructName: "JsonStruct", }, nil } func (p *Parser) Json2Struct() string { p.Output.appendSegment(p.StructTag, p.StructName) for parentName, parentValues := range p.Source { valueType := reflect.TypeOf(parentValues).String() if valueType == TYPE_INTERFACE { p.toParentList(parentName, parentValues.([]interface{}), true) } else { var fields Fields fields.appendSegment(parentName, FieldSegment{ Format: "%s", FieldValues: []FieldValue{ {CamelCase: false, Value: valueType}, }, }) p.Output.appendSegment("%s %s", fields[0].Name, fields[0].Type) } } p.Output.appendSuffix() return strings.Join(append(p.Output, p.Children...), "\n") } func (p *Parser) toChildrenStruct(parentName string, values map[string]interface{}) { p.Children.appendSegment(p.StructTag, parentName) for fieldName, fieldValue := range values { p.Children.appendSegment("%s %s", fieldName, reflect.TypeOf(fieldValue).String()) } p.Children.appendSuffix() } func (p *Parser) toParentList(parentName string, parentValues []interface{}, isTop bool) { var fields Fields for _, v := range parentValues { valueType := reflect.TypeOf(v).String() if valueType == TYPE_MAP_STRING_INTERFACE { fields = append(fields, p.handleParentTypeMapIface(v.(map[string]interface{}))...) p.Children.appendSegment(p.StructTag, parentName) for _, field := range fields.removeDuplicate() { p.Children.appendSegment("%s %s", field.Name, field.Type) } p.Children.appendSuffix() if isTop { valueType = word.UnderscoreToUpperCamelCase(parentName) } } if isTop { p.Output.appendSegment("%s %s%s", parentName, "[]", valueType) } break } } func (p *Parser) handleParentTypeMapIface(values map[string]interface{}) Fields { var fields Fields for fieldName, fieldValues := range values { var fieldValueType = reflect.TypeOf(fieldValues).String() var fieldSegment = FieldSegment{ Format: "%s", FieldValues: []FieldValue{{CamelCase: true, Value: fieldValueType}}, } switch fieldValueType { case TYPE_INTERFACE: fieldSegment = p.handleTypeIface(fieldName, fieldValues.([]interface{})) case TYPE_MAP_STRING_INTERFACE: fieldSegment = p.handleTypeMapIface(fieldName, fieldValues.(map[string]interface{})) } fields.appendSegment(fieldName, fieldSegment) } return fields } func (p *Parser) handleTypeIface(fieldName string, fieldValues []interface{}) FieldSegment { fieldSegment := FieldSegment{ Format: "%s%s", FieldValues: []FieldValue{ {CamelCase: false, Value: "[]"}, {CamelCase: true, Value: fieldName}, }, } p.toParentList(fieldName, fieldValues, false) return fieldSegment } func (p *Parser) handleTypeMapIface(fieldName string, fieldValues map[string]interface{}) FieldSegment { fieldSegment := FieldSegment{ Format: "%s", FieldValues: []FieldValue{ {CamelCase: true, Value: fieldName}, }, } p.toChildrenStruct(fieldName, fieldValues) return fieldSegment }

3.2.2 internal/json2struct/fields.go

go
type FieldSegment struct { Format string FieldValues []FieldValue } type FieldValue struct { CamelCase bool Value string } type Field struct { Name string Type string } type Fields []*Field func (f *Fields) appendSegment(name string, segment FieldSegment) { var s []interface{} for _, v := range segment.FieldValues { value := v.Value if v.CamelCase { value = word.UnderscoreToUpperCamelCase(v.Value) } s = append(s, value) } *f = append(*f, &Field{Name: word.UnderscoreToUpperCamelCase(name), Type: fmt.Sprintf(segment.Format, s...)}) } func (f *Fields) removeDuplicate() Fields { m := make(map[string]bool) fields := Fields{} for _, entry := range *f { if _, value := m[entry.Name]; !value { m[entry.Name] = true fields = append(fields, entry) } } return fields }

3.2.3 cmd/json.go

go
var jsonCmd = &cobra.Command{ Use: "json", Short: "json转换和处理", Long: "json转换和处理", Run: func(cmd *cobra.Command, args []string) {}, } var json2structCmd = &cobra.Command{ Use: "struct", Short: "json转换", Long: "json转换", Run: func(cmd *cobra.Command, args []string) { parser, err := json2struct.NewParser(str) if err != nil { log.Fatalf("json2struct.NewParser err: %v", err) } content := parser.Json2Struct() log.Printf("输出结果: %s", content) }, } func init() { jsonCmd.AddCommand(json2structCmd) json2structCmd.Flags().StringVarP(&str, "str", "s", "", "请输入json字符串") }

4.2.4 cmd/root.go

go
var rootCmd = &cobra.Command{} func Execute() error { return rootCmd.Execute() } func init() { rootCmd.AddCommand(wordCmd) rootCmd.AddCommand(timeCmd) rootCmd.AddCommand(sqlCmd) rootCmd.AddCommand(jsonCmd) }

4.2.5 验证

json这里有大坑,如果不是用文件读入,而是命令行输入json做测试,要注意,三个引号表示一个引号

go run main.go json struct --str '{ """name""":"""Southyang的文档库""","""url""":"""https://doc.southyang.cn""" }' 2022/05/20 14:50:18 输出结果: type JsonStruct struct { Name string Url string }

5. 最终目录结构

│ go.mod │ go.sum │ main.go │ ├─cmd 子命令集 │ json.go json struct : json转结构体 │ root.go 根命令 │ sql.go sql struct : sql转结构体 │ time.go time now/calc : 求当前时间和所需要的时间 │ word.go word : 字符串格式转换 │ ├─internal 逻辑函数 │ ├─json2struct │ │ fields.go │ │ parser.go │ │ │ ├─sql2struct │ │ mysql.go │ │ template.go │ │ │ ├─timer │ │ time.go │ │ │ └─word │ word.go │ └─pkg

目前的小工具都是从《Go语言编程之旅》上学的,以后遇到了问题也要总结自己的工具集了,冲冲冲

本文作者:southyang

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!