0%

golang标准库新增的学习

1. builtin

1.1 clear (go1.21.0)

对于map,清除删除所有条目,导致map为空。对于slice,清除将所有直到slice长度的元素设置为相应元素类型的零值。

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

import "fmt"

func main() {
m := map[string]string{
"1": "2",
"2": "2",
"3": "2",
}
fmt.Println(m, len(m))
clear(m)
fmt.Println(m, len(m))

s := []string{"1", "2", "3"}
fmt.Println(s, len(s))
clear(s)
fmt.Println(s, len(s), len(s[0]))
}

/*
map[1:2 2:2 3:2] 3
map[] 0
[1 2 3] 3
[ ] 3 0
*/

1.2 max & min (go1.21.0)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func main() {
fmt.Println(max(3.09, 3.10))
fmt.Println(min(50, 100))
fmt.Println(min("abc", "abcde"))
}
/*
3.1
50
abc
*/

2. bytes & string

2.1 Cut (go1.18)

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

import (
"bytes"
"fmt"
)

// 剪之前,剪之后,是否剪到
func main() {
show := func(s, sep string) {
before, after, found := bytes.Cut([]byte(s), []byte(sep))
fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found)
}
show("Gopher", "Go")
show("Gopher", "ph")
show("Gopher", "er")
show("Gopher", "Badger")

}

/*
Cut("Gopher", "Go") = "", "pher", true
Cut("Gopher", "ph") = "Go", "er", true
Cut("Gopher", "er") = "Goph", "", true
Cut("Gopher", "Badger") = "Gopher", "", false
*/

3. cmp

3.1 Compare

1
2
3
-1 if x is less than y,
0 if x equals y,
+1 if x is greater than y.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"cmp"
"fmt"
)

func main() {
fmt.Println(cmp.Compare(1, 2))
fmt.Println(cmp.Compare("a", "b"))
fmt.Println(cmp.Compare("b", "b"))
fmt.Println(cmp.Compare("c", "b"))
}
/*
-1
-1
0
1
*/

3.2 Or (go1.22.0)

1
2
fmt.Println(cmp.Or(8, 0, 1)) // 8
fmt.Println(cmp.Or(0, 1)) // 1

返回不等于零值的第一个参数。如果没有参数非零,则返回零值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import (
"cmp"
"fmt"
"slices"
)

func main() {
type Order struct {
Product string
Customer string
Price float64
}
orders := []Order{
{"foo", "alice", 1.00},
{"bar", "bob", 3.00},
{"baz", "carol", 4.00},
{"foo", "alice", 2.00},
{"bar", "carol", 1.00},
{"foo", "bob", 4.00},
}
// Sort by customer first, product second, and last by higher price
slices.SortFunc(orders, func(a, b Order) int {
return cmp.Or(
cmp.Compare(a.Customer, b.Customer),
cmp.Compare(a.Product, b.Product),
cmp.Compare(b.Price, a.Price),
)
})
for _, order := range orders {
fmt.Printf("%s %s %.2f\n", order.Product, order.Customer, order.Price)
}

}

/*
foo alice 2.00
foo alice 1.00
bar bob 3.00
foo bob 4.00
bar carol 1.00
baz carol 4.00
*/

4. context

4.1 WithoutCancel (go1.21.0)

1
func WithoutCancel(parent Context) Context

WithoutCancel returns a copy of parent that is not canceled when parent is canceled. The returned context returns no Deadline or Err, and its Done channel is nil. Calling Cause on the returned context returns nil.

4.2 AfterFunc (go1.21.0)

1
func AfterFunc(ctx Context, f func()) (stop func() bool)

AfterFunc 安排在 ctx 完成(取消或超时)后在自己的 goroutine 中调用 f。如果 ctx 已经完成,AfterFunc 会立即在自己的 goroutine 中调用 f。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package main

import (
"context"
"fmt"
"sync"
"time"
)

func main() {
waitOnCond := func(ctx context.Context, cond *sync.Cond, conditionMet func() bool) error {
stopf := context.AfterFunc(ctx, func() {
// We need to acquire cond.L here to be sure that the Broadcast
// below won't occur before the call to Wait, which would result
// in a missed signal (and deadlock).
cond.L.Lock()
defer cond.L.Unlock()

// If multiple goroutines are waiting on cond simultaneously,
// we need to make sure we wake up exactly this one.
// That means that we need to Broadcast to all of the goroutines,
// which will wake them all up.
//
// If there are N concurrent calls to waitOnCond, each of the goroutines
// will spuriously wake up O(N) other goroutines that aren't ready yet,
// so this will cause the overall CPU cost to be O(N²).
cond.Broadcast()
})
defer stopf()

// Since the wakeups are using Broadcast instead of Signal, this call to
// Wait may unblock due to some other goroutine's context becoming done,
// so to be sure that ctx is actually done we need to check it in a loop.
for !conditionMet() {
cond.Wait()
if ctx.Err() != nil {
return ctx.Err()
}
}

return nil
}

cond := sync.NewCond(new(sync.Mutex))

var wg sync.WaitGroup
for i := 0; i < 4; i++ {
wg.Add(1)
go func() {
defer wg.Done()

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()

cond.L.Lock()
defer cond.L.Unlock()

err := waitOnCond(ctx, cond, func() bool { return false })
fmt.Println(i, err)
}()
}
wg.Wait()

}


/*
2 context deadline exceeded
3 context deadline exceeded
0 context deadline exceeded
1 context deadline exceeded
*/

10. 参考资料

可以加首页作者微信,咨询相关问题!