Go1.18 新特性:弃用 strings.Title 方法,换个新坑吧!♀?♀大家好,我是煎鱼。最近在看 Go1.18 Release Notes 时,发现 strings, bytes 标准库的 Title 方法,竟然被弃用了(Deprecated),这是为什么呢?今天这篇文章就由煎鱼和大家一起看看。介绍这里以 strings 标准库为例,strings.Title 方法的作用是:将所有单词开头的 Unicode 字母映射到其 Unicode 标题大小写。例子如下:import ( "fmt" "strings")func main() { fmt.Println(strings.Title("her royal highness")) fmt.Println(strings.Title("eddy cjy")) fmt.Println(strings.Title("хлеб"))}输出结果:Her Royal HighnessEddy CjyХлеб这些单词均被转换为其大写。问题看上去似乎一切都很美好,但其实他现阶段有 2 个明显的缺陷。分别是:无法正确处理 Unicode 标点符号。不考虑特定人类语言的大写规则。接下来我们具体展开讲讲。Unicode 标点符号第一个问题,例子如下:import ( "fmt" "strings")func main() { a := strings.Title("go.go\u2024go") b := "Go.Go\u2024Go" if a != b { fmt.Printf("%s != %s\n", a, b) }}输出结果:Go.Go?go != Go.Go?Go变量 a 转换处理的结果是 “Go.Go?go”,但按照实际的诉求应当为 “Go.Go?Go”。特定语言规则第二个问题,代码如下:func main() { fmt.Println(strings.Title("ijsland"))}输出结果:Ijsland在荷兰语的单词中,“ijsland” 应大写为 “IJsland”,但结果转换为 “Ijsland”。解决方案这个问题在 2013 年就发现了,来源于♀?♀,被 Go 语言之父 Rob Pike 标识为计划外的问题。如下图:由于 Go1 兼容性保障的条约,因此这是 “无法” 修复的,一旦修复就会影响函数的输出结果,是破坏性变更。但也可以采取别的方式,也就是本文中提到的 “弃用”。如下标识:// Title returns a copy of the string s with all Unicode letters that begin words// mapped to their Unicode title case.//// BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly.//// Deprecated: Use golang.org/x/text/cases instead.func Title(s string) string {在函数上标识 “Deprecated”:对应 Go 文档会将其折叠并明确显示弃用,建议直接使用 golang.org/x/text/cases 库来实现该功能。新的 x/text/cases 案例如下:import ( "fmt" "golang.org/x/text/cases" "golang.org/x/text/language")func main() { src := []string{ "hello world!", "i with dot", "'n ijsberg", "here comes O'Brian", } for _, c := range []cases.Caser{ cases.Lower(language.Und), cases.Upper(language.Turkish), cases.Title(language.Dutch), cases.Title(language.Und, cases.NoLower), } { fmt.Println() for _, s := range src { fmt.Println(c.String(s)) } }}输出结果:hello world!i with dot'n ijsberghere comes o'brianHELLO WORLD!? W?TH DOT'N ?JSBERGHERE COMES O'BR?ANHello World!I With Dot'n IJsbergHere Comes O'brianHello World!I With Dot'N IjsbergHere Comes O'Brian输出了多种语言的转换,我们核心关注 cases.Lower(language.Und) 相关的代码,该库会通过调用:cases.Title(<language>).Bytes(<bytes>)cases.Title(<language>).String(<string>)在编程中指定处理的语言,来解决不同人类语言的符号、不同语言和大写词语的诉求,避免一刀切。总结虽然只有一个小小的函数,但也延伸出了不少的问题。本质上还是在设计时,存在认知的局限性。另外 strings.Title 和 bytes.Title 函数,在实际工作中也常被误解为就是转换首字母大写的方法,与设计含义相违背。虽然最终与缺陷相比,这样的误解却带来了更好的效果,但对于一些特殊场景和语言支持,还是有很大的问题。也算是塞翁失马,焉知非福了。若有任何疑问欢迎评论区反馈和交流,最好的关系是互相成就,各位的点赞就是煎鱼创作的最大动力,感谢支持。文章持续更新,可以微信搜【脑子进煎鱼了】阅读,本文 GitHub github.com/eddycjy/blog 已收录,学习 Go 语言可以看 Go 学习地图和路线,欢迎 Star 催更。
