Franz`s blog

go学习笔记和一些语法糖

… 的用法

可变参数

1
2
3
4
5
func a(args ...int) int {
for _, val := range args {
// do something
}
}

打散slice

1
2
3
4
5
6
7
8
9
10
func a() {
s := []int{1, 2, 3}
b(s...) // 这里的slice {1,2,3} 被打散为 1,2,3 传入函数b
}

func b(args2 ...int) {
for _, i := range args2 {
// do something
}
}

go中的继承

先看一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type (
RouterGroup struct {
prefix string
middlewares []HandlerFunc
parent *RouterGroup
engine *Engine
}

Engine struct {
*RouterGroup
router *router
groups []*RouterGroup
}
)

可以看到上面Engine中包含了*RouterGroup这一匿名字段,Engine 结构体将直接继承 RouterGroup 中的所有字段和方法,并且不需要使用 .prefix.middlewares.parent 等字段来引用 RouterGroup 中的属性和方法,而可以直接使用 Engine 实例进行访问。

go tag

tag 是一种结构化的注释方式,它可以用于给结构体字段添加元数据,例如字段的名称、类型、格式、验证规则等信息。

示例如下

1
2
3
4
type Person struct {
Name string `json:"name" xml:"name"`
Age int `json:"age" xml:"age"`
}

可以最终通过反射拿到tag的k-v信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fmt"
"reflect"
)

type Person struct {
Name string `json:"name" xml:"name"`
Age int `json:"age" xml:"age"`
}

func main() {
p := Person{Name: "Alice", Age: 25}
t := reflect.TypeOf(p)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag
fmt.Printf("Field: %s, JSON tag: %s, XML tag: %s\n",
field.Name, tag.Get("json"), tag.Get("xml"))
}
}

cap和len

caplen 都是内置函数,用于获取切片、数组、map 和 channel 的长度和容量信息。

slice作为一个array的引用其cap和len并不一定相等,slice的容量可以动态扩展,如果在使用 append 函数将元素添加到切片时长度超过了当前容量,Go 会动态分配一块更大的内存作为底层数组,并将原有数据复制到新的内存空间中,完成切片的扩容过程。如果切片的长度没有超过容量,则不会进行扩容。这个过程会导致切片的地址发生变化。可以通过对比改变前后切片的地址来判断是否扩容。

any

在go1.18之后添加的新关键字 all: rewrite interface{} to any #49884

等同于之前的interface{}

1
type any interface{}

用法

1
2
3
4
5
6
7
8
func a(v any) {
switch v.(type) {
case int:
fmt.Println("int type val")
case bool:
fmt.Println("bool type val")
}
}