Go1.24 新特性:更多的迭代器方法、JSON 支持省略零值、终结器的改进等

开发 前端
本次新版本增加的 runtime.AddCleanup​ 函数是一个比原有 runtime.SetFinalizer 更灵活、更高效且更不易出错的终结机制。

大家好,我是煎鱼。

今天给大家继续介绍 Go1.24 的新特性,主要涉及垃圾回收时的注册函数机制、新增的迭代器方法、JSON 零值的优化。

改进的终结器(finalizer)

本次新版本增加的 runtime.AddCleanup 函数是一个比原有 runtime.SetFinalizer 更灵活、更高效且更不易出错的终结机制。

AddCleanup 允许为对象附加一个清理函数,该函数会在对象不可达时执行。

例如像如下案例的代码:

func main() {
 e := newExample(233)
 fmt.Printf("e=%v, type=%T\n", e, e)
}

type Example []byte

func (b Example) String() string {
 return fmt.Sprintf("Example(%d KB)", len(b)/1024)
}

func newExample(size int) *Example {
 b := make([]byte, size*1024)
 for i := range size {
  b[i] = byte(i) % 255
 }
 return (*Example)(&b)
}

如果我们希望在 Example 被垃圾回收时运行一个清理函数,现在可以直接借用 runtime.AddCleanup 就可以很便捷的达到目的了。

引入 runtime.AddCleanup 函数后,如下 Go1.24 的新版本代码:

func cleanup(created time.Time) {
 fmt.Printf(
  "object is cleaned up! lifetime = %dms\n",
  time.Since(created)/time.Millisecond,
 )
}

func main() {
 e := newExample(233)

 now := time.Now()
 runtime.AddCleanup(e, cleanup, now)
 time.Sleep(10 * time.Millisecond)
 e = nil
 runtime.GC()
 time.Sleep(10 * time.Millisecond)
}

输出结果:

object is cleaned up! lifetime = 10ms

可以看到该函数顺利在 newExample 结束后进行垃圾回收时运行了提前注册的函数。

slog 增加丢弃标识 Discard

Go1.24 新版本中添加一个包级变量 slog.DiscardHandler(类型为 slog.Handler),用于丢弃所有日志输出。

提案如下:

图片图片

以前想要达到这个目的的话,slog 代码需要写成如下这样:

func main() {
 log := slog.New(
  slog.NewTextHandler(io.Discard, nil),
 )
 log.Info("脑子进煎鱼了...")
}

现在新版本后,代码直接这么写即可:

func main() {
 log := slog.New(slog.DiscardHandler)
 log.Info("脑子进煎鱼了!")
}

增加 strings 标准库迭代器方法

strings.Lines

Lines 函数签名:

func Lines(s string) iter.Seq[string]

Lines 返回字符串 s 中换行结束行 \n 的迭代器。如果 s 为空,则迭代器不会产生任何行。如果 s 不以换行结束,则最后生成的行也不会以换行结束。

该迭代器返回一个一次性使用的迭代器。

示例代码:

func main() {
 s := "脑子\n进\n煎鱼了"
 for line := range strings.Lines(s) {
  fmt.Print(line)
 }
}

输出结果:

脑子
进
煎鱼了

strings.SplitSeq

SplitSeq 函数签名:

func SplitSeq(s, sep string) iter.Seq[string]

SplitSeq 返回用 sep 分隔的 s 的所有子串的迭代器。该迭代器产生的字符串与 Split(s, sep) 返回的字符串相同,但不构造切片。

该迭代器返回一个一次性使用的迭代器。

示例代码:

func main() {
 s := "脑子-进-煎鱼了"
 for part := range strings.SplitSeq(s, "-") {
  fmt.Println(part)
 }
}

输出结果:

脑子
进
煎鱼了

strings.SplitAfterSeq

SplitAfterSeq 函数签名:

func SplitAfterSeq(s, sep string) iter.Seq[string]

SplitAfterSeq 返回在每个 sep 实例之后分割的 s 子串的迭代器。该迭代器产生的字符串与 SplitAfter(s, sep) 返回的字符串相同,但不需要构造切片。

该迭代器返回一个一次性使用的迭代器。

示例代码:

func main() {
 s := "脑子-进-煎鱼了"
 for part := range strings.SplitAfterSeq(s, "-") {
  fmt.Println(part)
 }
}

输出结果:

脑子-
进-
煎鱼了

strings.FieldsSeq

FieldsSeq 函数签名:

func FieldsSeq(s string) iter.Seq[string]

根据 unicode.IsSpace 的定义,FieldsSeq 返回围绕空白字符串分割的 s 子串的迭代器。迭代器产生的字符串与 Fields(s) 返回的字符串相同,但不需要构建切片。

示例代码:

func main() {
 s := "脑子 进\n煎鱼了"
 for part := range strings.FieldsSeq(s) {
  fmt.Println(part)
 }
}

输出结果:

脑子
进
煎鱼了

strings.FieldsFuncSeq

FieldsFuncSeq 函数签名:

func FieldsFuncSeq(s string, f func(rune) bool) iter.Seq[string]

FieldsFuncSeq 返回围绕满足 f(c) 的 Unicode 代码点运行分割的 s 子串的迭代器。迭代器产生的字符串与 FieldsFunc(s) 返回的字符串相同,但不需要构建切片。

示例代码:

func main() {
 f := func(c rune) bool {
  return !unicode.IsLetter(c) && !unicode.IsNumber(c)
 }

 s := "脑子,进;煎鱼了..."
 for part := range strings.FieldsFuncSeq(s, f) {
  fmt.Println(part)
 }
}

输出结果:

脑子
进
煎鱼了

json.Marshal 支持省略零值

时隔近 4 年,Go 终于在 1.24 中支持 JSON 省略零值。这是很多同学在开发过程中比较烦恼的问题。这回总算是有个解决的口子了。

相关提案:

图片图片

以前我们使用 omitempty 标签时:

type Person struct {
 Name      string    `json:"name"`
 BirthDate time.Time `json:"birth_date,omitempty"`
}

func main() {
 eddycjy := Person{Name: "煎鱼"}
 b, err := json.Marshal(eddycjy)
 fmt.Println(string(b), err)
}

输出结果:

{"name":"煎鱼","birth_date":"0001-01-01T00:00:00Z"} <nil>

可以看到 birth_date 是有零值结果的。

在 Go1.24 新版本后,可以使用 omitzero 标签:

type Person struct {
 Name      string    `json:"name"`
 BirthDate time.Time `json:"birth_date,omitzero"`
}

func main() {
 eddycjy := Person{Name: "煎鱼"}
 b, err := json.Marshal(eddycjy)
 fmt.Println(string(b), err)
}

输出结果:

{"name":"煎鱼"} <nil>

可以看到 JSON 后 birth_date 的零值没有了。只有 name 的值结果。符合使用预期。

总结

这次 Go1.24 还是可以的,带来了一些比较实用的新特性方法。尤其是像是 JSON 零值等用法,可以有效解决一些小痛点。

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

2025-01-06 09:18:04

2024-12-30 11:05:28

泛型Go类型别名

2024-12-23 08:44:49

2025-01-20 08:51:32

2024-09-03 08:49:01

2022-05-05 11:20:08

KubernetesDocker云计算

2024-09-09 08:56:03

2024-11-19 09:10:19

迭代器Go语言

2022-12-09 08:52:51

Go匿名接口

2024-08-07 08:51:20

Go优化开发

2010-05-13 18:05:34

IIS服务器

2014-12-04 10:47:18

Java 9

2022-01-26 09:02:57

GoCut方法

2013-05-02 09:14:19

Java 8Java 8的新特性

2021-10-20 16:44:50

Windows 11操作系统微软

2009-09-04 16:28:05

ASP.NET 4.0

2024-09-02 00:30:41

Go语言场景

2022-01-26 00:02:01

Go二进制元信息

2020-09-02 14:08:04

Kotlin语言开发者

2022-02-11 21:01:18

GoNetip网络库
点赞
收藏

51CTO技术栈公众号