Go笔记(9)编程模式

这篇记录编程模式。包含反射编程、不安全编程。

反射

• reflect.TypeOf 返回类型 (reflect.Type)
• reflect.ValueOf 返回值 (reflect.Value)
• 可以从 reflect.Value 获得类型
• 通过 Kind 的来判断类型

1
2
3
4
5
6
7
8
9
10
11
func CheckType(v interface{}) {
t := reflect.TypeOf(v)
switch t.Kind() { // Kind返回类型的枚举
case reflect.Float32, reflect.Float64:
fmt.Println("Float")
case reflect.Int, reflect.Int32, reflect.Int64:
fmt.Println("Integer")
default:
fmt.Println("Unknown", t)
}
}

• reflect.ValueOf(*e).FieldByName(“Name”) 按名字访问结构的成员
• reflect.ValueOf(e).MethodByName(“UpdateAge”).Call([]reflect.Value{reflect.ValueOf(1)}) 按名字访问结构的⽅法

1
2
3
4
5
6
7
8
9
10
type Employee struct {
Name string `format:"normal"` // tag
}
reflect.ValueOf(*e).FieldByName("Name")
// TypeOf第一个返回值为field,第二个返回值为field是否存在
if nameField, ok := reflect.TypeOf(*e).FieldByName("Name"); !ok {
t.Error("Failed to get 'Name' field.")
} else {
t.Log("Tag:format", nameField.Tag.Get("format"))
}

不安全编程

不能使用 unsafe 进行强制类型转换,合理的类型转换如下:

1
2
3
4
5
6
type MyInt int
func TestConvert(t *testing.T) {
a := []int{1, 2, 3, 4}
b := *(*[]MyInt)(unsafe.Pointer(&a))
t.Log(b)
}

原子类型操作:适用于并发读写操作,为了线程安全,可以先写在另一块区域,完全写完之后利用原子操作,将 buffer 指向写完的内容。

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
func TestAtomic(t *testing.T) {
var shareBufPtr unsafe.Pointer
writeDataFn := func() {
data := []int{}
for i := 0; i < 100; i++ {
data = append(data, i)
}
atomic.StorePointer(&shareBufPtr, unsafe.Pointer(&data))
}
readDataFn := func() {
data := atomic.LoadPointer(&shareBufPtr)
fmt.Println(data, *(*[]int)(data))
}
var wg sync.WaitGroup
writeDataFn()
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
for i := 0; i < 10; i++ {
writeDataFn()
time.Sleep(time.Microsecond * 100)
}
wg.Done()
}()
wg.Add(1)
go func() {
for i := 0; i < 10; i++ {
readDataFn()
time.Sleep(time.Microsecond * 100)
}
wg.Done()
}()
}
wg.Wait()
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!