1

大家好,我是煎鱼。

最近介绍了 Go1.23 的几个重要新特性。今天给大家分享一些本次新版本的方法/函数的功能优化、改进的汇总。

主打一个快速知悉,跟上新用法。看看 rsc 在 Go 核心团队负责人的职业生涯最后都推动了什么函数的合入。

Go1.23 方法/函数优化

slices.Repeat

这是一个今年(2024 年)才提出的新提案,原提案作者提供给功能介绍时,还给出了其他语言的相关案例。很快受到了 Go 官方团队的响应并通过。

函数签名:

func Repeat[S ~[]E, E any](x S, count int "S ~[]E, E any") S

Repeat 方法会返回一个新的切片,函数的作用是将所提供的切片,按给定的次数进行重复。

注意:如果 count 为负数或溢出,该方法会触发 panic 事件。

Go1.23 代码例子如下:

import (
    "fmt"
    "slices"
)

func main() {
    s := []string{"煎鱼", "咸鱼", "摸鱼"}
    repeat := slices.Repeat(s, 2)
    fmt.Println(repeat)
}

输出结果:

[煎鱼 咸鱼 摸鱼 煎鱼 咸鱼 摸鱼]

os.DirFS

这个新提案由 rsc 于 2023 年从 2021 年的旧提案转化过来,目的上是为了更安全地将目标文件复制到本地文件系统,认为可以帮助到很多场景。

函数签名:

func DirFS(dir string) fs.FS

os.DirFS 方法返回以目录 dir 为根的文件树的文件系统(fs.FS),再结合 os.CopyFS 方法可以实现一次性的递归复制文件和目录。

Go1.23 代码例子如下:

src := os.DirFS("/Users/eddycjy/hello.txt")
dst := "/tmp/hello.txt"

err := os.CopyFS(dst, src)
if err != nil {
    panic(err)
}

fmt.Printf("copied %s to %s\n", src, dst)

panic

在 Go1.22 及以前的版本,运行以下代码:

func main() {
    panic("脑子\n进\nI\n煎鱼了")
}

输出结果如下:

panic: 脑子
进
I
煎鱼了

goroutine 1 [running]:
main.main()
    /tmp/sandbox3096848362/prog.go:6 +0x25

Go1.23 新版本起,输出结果将会变成:

panic: 脑子
    进
    I
    煎鱼了

goroutine 1 [running]:
main.main()
    /tmp/sandbox1717599036/prog.go:6 +0x25

新版本后,panic 函数会用制表符缩进错误信息(如 panic 的参数)的第二行和后续行,以区别于第一个 goroutine 的堆栈跟踪。

http.ParseCookie/ParseSetCookie

现在在 Go 程序中,如果我们要从 cookie 标头字符串中提取 cookie 结构体。需要编写以下类似的代码:

req := http.Request{Header: http.Header{"Cookie": []string{raw}}}
cookies := req.Cookies()

虽然从原提案的角度来看还能用。但是终究绕了几层才把东西取到,也不方便。

因此 @Eyal Posener 在 2018 年提出了 x/net/http/httpguts: add ParseCookie and ParseSetCookie 的新提案诉求。在 2024 年,rsc 重新把这活拎了出来,加进了新版本中。

本次 Go1.23 是在 net.http 标准库中新增了如下两个方法:

  1. ParseCookie
  2. ParseSetCookie

ParseCookie

函数签名:

func ParseCookie(line string) ([]*Cookie, error)

ParseCookie 解析 Cookie 标头值并返回其中设置的所有 Cookie。

Go1.23 代码例子如下:

func main() {
    lines := "session_id=eddycjy; value=hello-world; lang=en; lang=zh-CN"
    cookies, _ := http.ParseCookie(lines)
    for _, cookie := range cookies {
        fmt.Printf("%s: %s\n", cookie.Name, cookie.Value)
    }
}

输出结果:

session_id: eddycjy
value: hello-world
lang: en
lang: zh-CN

如果存在多个相同字段,将会返回多次。

ParseSetCookie

函数签名:

func ParseSetCookie(line string) (*Cookie, error)

ParseSetCookie 函数解析 Set-Cookie 标头值并返回 Cookie。

Go1.23 代码例子如下:

func main() {
    line := "session_id=eddycjy; MaxAge=0; lang=zh-CN; Domain=.eddycjy.com"
    cookie, _ := http.ParseSetCookie(line)

    fmt.Println("Name:", cookie.Name)
    fmt.Println("Value:", cookie.Value)
    fmt.Println("Domain:", cookie.Domain)
    fmt.Println("MaxAge:", cookie.MaxAge)
}

输出结果:

Name: session_id
Value: eddycjy
Domain: .eddycjy.com
MaxAge: 0

在解析结果上,主要是对标 Cookie,有预定义的标准字段:

type Cookie struct {
    Name  string
    Value string

    Path       string    // optional
    Domain     string    // optional
    Expires    time.Time // optional
    RawExpires string    // for reading cookies only

    // MaxAge=0 means no 'Max-Age' attribute specified.
    // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
    // MaxAge>0 means Max-Age attribute present and given in seconds
    MaxAge   int
    Secure   bool
    HttpOnly bool
    SameSite SameSite
    Raw      string
    Unparsed []string // Raw text of unparsed attribute-value pairs
}

如果有自定义字段需要读取的,可以使用 Cookie.Raw 读取到原始的字符串进行解析和额外处理。

总结

今天给大家分享了一些 Go1.23 新版本的新方法、函数,目前来看这些函数没有特别大的功能调整,主要都是对于日常工程开发上的优化。

这些新调整也算是针对开发效率的一定的提效了,大家可以及时用到工作的开发上!

  • 本文作者:煎鱼
  • 公众号:脑子进煎鱼了
  • 联系方式(微信号):cJY0728(加我拉你进技术交流群)
文章持续更新,可以微信搜【脑子进煎鱼了】阅读,本文 GitHub github.com/eddycjy/blog 已收录,学习 Go 语言可以看 Go 学习地图和路线,欢迎 Star 催更。

推荐阅读


煎鱼
8.4k 声望12.8k 粉丝