Go1.18 新特性:弃用 strings.Title 方法,换个新坑吧!

开发 前端
最近在看 Go1.18 Release Notes 时,发现 strings, bytes 标准库的 Title 方法,竟然被弃用了(Deprecated),这是为什么呢?

本文转载自微信公众号「脑子进煎鱼了」,作者陈煎鱼。转载本文请联系脑子进煎鱼了公众号。

大家好,我是煎鱼。

最近在看 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 Highness
Eddy 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 年就发现了,来源于《strings: Title function incorrectly handles word breaks[1]》,被 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”:

​https://pkg.go.dev ​

对应 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 ijsberg
here comes o'brian

HELLO WORLD!
İ WİTH DOT
'N İJSBERG
HERE COMES O'BRİAN

Hello World!
I With Dot
'n IJsberg
Here Comes O'brian

Hello World!
I With Dot
'N Ijsberg
Here Comes O'Brian

输出了多种语言的转换,我们核心关注 cases.Lower(language.Und) 相关的代码,该库会通过调用:

  • cases.Title(<language>).Bytes(<bytes>)
  • cases.Title(<language>).String(<string>)

在编程中指定处理的语言,来解决不同人类语言的符号、不同语言和大写词语的诉求,避免一刀切。

但这个新 “坑”,显然也引入了更多的复杂性,说好的 “less is more...”,使用该方法时值得考量新的成本了。

总结

虽然只有一个小小的函数,但也延伸出了不少的问题。本质上还是在设计时,存在认知的局限性。

另外 strings.Title 和 bytes.Title 函数,在实际工作中也常被误解为就是转换首字母大写的方法,与设计含义相违背。

虽然最终与缺陷相比,这样的误解却带来了更好的效果,但对于一些特殊场景和语言支持,还是有很大的问题。

也算是塞翁失马,焉知非福了。

参考资料

[1]strings: Title function incorrectly handles word breaks: https://github.com/golang/go/issues/6801


责任编辑:武晓燕 来源: 脑子进煎鱼了
相关推荐

2022-01-26 09:02:57

GoCut方法

2022-02-11 21:01:18

GoNetip网络库

2022-01-19 08:51:00

Module工作区Go

2022-02-14 09:32:49

Go场景TryLock

2021-12-27 18:27:18

GoTryLockJava

2021-12-02 18:21:49

GoIP 包设计

2022-01-26 00:02:01

Go二进制元信息

2021-12-28 07:20:44

泛型Go场景

2021-09-05 18:25:30

Go命令仓库

2021-12-15 12:59:56

Go泛型版Beta1

2024-01-22 00:30:00

Go编程Go 1.22

2022-03-18 18:00:00

编程语言泛型支持模糊测试

2022-09-13 09:46:44

Go开发者调查Go 1.18

2021-12-15 10:23:56

Go 1.18 Bet语言泛型

2009-08-27 16:24:48

扩展方法C# 3.0新特性

2021-02-02 09:10:12

Go语言二进制

2014-07-15 14:48:26

Java8

2014-07-15 13:57:53

Java8

2022-05-17 08:02:55

GoTryLock模式

2021-09-01 07:21:46

堆栈Gopanic
点赞
收藏

51CTO技术栈公众号