go 汉字转拼音 go-pinyin

前言 本文介绍一个 go 汉字转拼音的库 go-pinyin,可以从名字看出这个库的功能就是将汉字转换为相应的拼音。接下来就由我来简单的介绍 go-pinyin 。 安装 使用此命令安装: go get github.com/mozillazg/go-pinyin cli 安装 如果你的 go 版本在 1.17 以下使用此命令安装: go get -u github.com/mozillazg/go-pinyin/cli/pinyin。1.17及以上版本使用此命令安装:go install github.com/mozillazg/go-pinyin/cli/pinyin@latest。 使用 接下来将分别介绍 cli 的使用和 API 的使用。 cli 使用 安装完在终端输入 pinyin,可以看到使用的方法,尝试一个汉字,可以看到相应的拼音,但也可以看出对多音字的支持有问题。 $ pinyin 中国 zhōng guó $ pinyin 重庆 zhòng qìng 接下来介绍 API 的使用。 api 使用 通过查看文档,可以看出主要是2个方法 pinyin.NewArgs 和 pinyin.Pinyin 。 pinyin.NewArgs 创建包含默认配置的 Args, 可以通过修改 Args 的成员来使用不同的模式。 type Args struct { Style int // 拼音风格(默认: Normal) Heteronym bool // 是否启用多音字模式(默认:禁用) Separator string // Slug 中使用的分隔符(默认:-) // 处理没有拼音的字符(默认忽略没有拼音的字符) // 函数返回的 slice 的长度为0 则表示忽略这个字符 Fallback func(r rune, a Args) []string } pinyin.Pinyin 就是将汉字转为拼音。 ...

十二月 23, 2023 · overstarry

mergo 介绍

前言 今天介绍一个 go 库 - mergo, mergo 用来方便的合并 struct 和 map ,可以将结构体的字段赋值到map中,可以将map的值赋值给结构体的字段. Mergo 通过在零值字段中设置默认值来合并同类型的struct 和 map。Mergo 不会合并未导出(私有)字段。它会递归合并任何已导出的字段。它也不会合并map中的结构体(因为它们无法使用 Go 反射寻址)。 Mergo 在很多知名项目中被使用,如 containerd、k8s、loki等。 安装 使用以下命令安装 mergo : go get -u dario.cat/mergo 使用 接下来介绍 mergo 的基础使用和高级用法。 基础使用 mergo 提供了2个主要函数: Merge和Map, Mergo 用来合并2个相同结构的 struct 和 map, Map 用来在结构和map之间赋值。 例子: package main import ( "fmt" "log" "github.com/imdario/mergo" ) type redisConfig struct { Address string Port int DB int UserName string PassWord string } var defaultConfig = redisConfig{ Address: "127.0.0.1", Port: 6379, DB: 1, UserName: "123", PassWord: "123", } func main() { var config redisConfig if err := mergo.Merge(&config, defaultConfig); err != nil { log.Fatal(err) } fmt.Println("redis address: ", config.Address) fmt.Println("redis port: ", config.Port) fmt.Println("redis db: ", config.DB) fmt.Println("redis username: ", config.UserName) fmt.Println("redis password: ", config.PassWord) var m = make(map[string]interface{}) if err := mergo.Map(&m, defaultConfig); err != nil { log.Fatal(err) } fmt.Println(m) } 接下来介绍一些高级用法: ...

十二月 16, 2023 · overstarry

conc 一个更好的go并发库

前言 本文介绍 conc - 一个更好的 go 并发库, sourcegraph 在日常开发中使用go原生并发出现了问题,由此开发了 conc ,相比标准并发代码更优雅,代码更少,下面展示一个例子,可以看出代码减少了许多. type propagatedPanic struct { val any stack []byte } func main() { done := make(chan *propagatedPanic) go func() { defer func() { if v := recover(); v != nil { done <- &propagatedPanic{ val: v, stack: debug.Stack(), } } else { done <- nil } }() doSomethingThatMightPanic() }() if val := <-done; val != nil { panic(val) } } // conc func main() { var wg conc.WaitGroup wg.Go(doSomethingThatMightPanic) // panics with a nice stacktrace wg.Wait() } 安装 使用以下命令进行安装: go get github.com/sourcegraph/conc ...

十二月 9, 2023 · overstarry

Go设计模式-策略模式

今天介绍一个常见的设计模式-策略模式,并基于一个简单的例子来讲解。 策略模式介绍 策略模式(Strategy Pattern)是一种行为型设计模式,它将一组算法封装成独立的对象,并使它们可以互相替换。这样做的好处是,可以在运行时动态地改变对象的行为,而不需要修改使用该对象的代码。 何时可以使用策略模式呢 我们在用GO编程的时候经常碰到多层控制语句,一层又一层,既不优雅,也不利于后续维护。比如下述这种: if xxx { // do something } else if xxx { // do something } else if xxx { // do something else { } 虽然按这种模式写起来简单快捷,但它也违背了面向对象的两个原则: 单一职责原则:多个控制语句,意味着拥有多种功能; 开闭原则:当要进行修改时,原有代码不可避免要被修改; 此时就可以采用策略模式来替换这类多层控制语句。 go 实现策略模式 go 语言该怎么实现策略模式呢? 在Go语言中,策略模式可以通过接口和函数来实现。首先,我们定义一个接口,该接口声明了算法执行的方法。然后,我们可以为每个具体的算法实现一个结构体,并实现接口中的方法。最后,我们可以在需要使用算法的地方,通过接口来调用具体的算法。 下面通过一个简单的例子来讲解策略模式, 现在有这样一个场景我们现在有2个数据表,这2个数据表拥有相同的字段,都可以根据 name 来查询某个数据,我们需要根据参数的不同来决定使用哪种表进行查询, 在没有使用策略模式时, 我们往往使用大量的if来实现这个操作。 接下来由我来介绍策略模式来实现相同的操作。 先定义查询操作的接口: type DataStrategy interface { Query(name string) } 定义2张表的查询struct,并实现DataStrategy接口: // table1 通过table1 来查询 type table1 struct{} func (s *table1) Query(name string) { fmt.Println("table1 query") } // table2 type table2 struct{} func (s *table2) Query(name string) { fmt.Println("table2 query") } 再定义 Data 对象用来执行不同的策略: ...

十一月 11, 2023 · overstarry

Go1.22 新循环语义

前言 前段时间看到了一个提案,是关于 go for 循环的一个提案,根据提案看到了去年 rsc 在社区发出的讨论,讨论的内容主要是为了解决 for 循环变量的问题,是什么样的问题呢,常见的例子如下: var all []*Item for _, item := range items { all = append(all, &item) } 这段代码有一个问题,循环结束后,all 的内容是包含了 len(all) 个相同的指针,指针指向迭代的最后一个 item。为什么会发生这种情况呢,因为 item 变量是每个循环的而不是每次迭代的,&item每次迭代都是相同的,并且每次迭代都会被覆盖。 怎么解决呢,最简单的方法就是添加 item := item 这段代码: var all []*Item for _, item := range items { item := item all = append(all, &item) } 我在使用 Goroutine 协程时也经常遇到这种问题。这种错误已导致许多公司出现生产问题,包括 Lets Encrypt 公开记录的问题。 go 社区为了解决这个问题,打算将循环变量改为每次迭代,即隐式的添加上面的代码。由于其它一些原因,直到今年的6月才正式决定在 go 1.21 中添加 GOEXPERIMENT=loopvar 进行相应的尝试,并且将在 go1.22 版本中正式推出。 为了确保与现有代码的向后兼容性,新语义将仅适用于声明go 1.22或稍后在其go.mod文件中声明的模块中包含的包。 特性测试 我们通过不同版本运行的结果来对比 package main import "fmt" func main() { var prints []func() for _, v := range []int{1, 2, 3} { prints = append(prints, func() { fmt.Println(v) }) } for _, print := range prints { print() } } 没使用旧版本运行的结果是: ...

十一月 4, 2023 · overstarry