Go语言学习12-反射和Unsafe

Go语言学习12-反射和Unsafe

reflect.TypeOf vs. reflect.ValueOf

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

判断类型——Kind()

func CheckType(v interface{}) {
	t := reflect.TypeOf(v)
	switch t.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)})

Struct Tag

type BasicInfo struct {
	Name string `json:"name"`
	Age  int 	`json:"age"`
}
访问 StructTag
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"))
}

Reflect.Type 和 Reflect.Value 都有 FieldByName ⽅方法,注意他们的区别

万能程序

func FillBySettings(st interface{}, settings map[string]interface{}) error {
	// func(v value) Elem() Value
	// elem returns the value that the interface v contains or that the pointer v points to.
	// It panics if v's Kind is not Interface or Ptr
	// It returns the zero Value if v is nil.

	if reflect.TypeOf(st).Kind() != reflect.Ptr {
		// Elem() 获取指针指向的值
		if reflect.TypeOf(st).Elem().Kind() != reflect.Struct {
			return errors.New("the first param should be a pointer to the struct type")
		}
	}
	
	if settings == nil {
		return errors.New("settings is nil")
	}
	var (
		field reflect.StructField
		ok    bool
	)

	for k, v := range settings {
		if field, ok = (reflect.ValueOf(st)).Elem().Type().FieldByName(k); !ok {
			continue
		}
		if field.Type == reflect.TypeOf(v) {
			vstr := reflect.ValueOf(st)
			vstr = vstr.Elem()
			vstr.FieldByName(k).Set(reflect.ValueOf(v))
		}
	}
	return nil
}

反射的特点

  • 提高了程序的灵活性
  • 降低了程序的可读性
  • 降低了程序的性能

“不安全” 编程

func TestUnsafe(t *testing.T) {
	i := 10
	f := *(*float64)(unsafe.Pointer(&i))
	t.Log(unsafe.Pointer(&i))
	t.Log(f)
}

// The cases is suitable for unsafe
type MyInt int

// 合理的类型转换
func TestConvert(t *testing.T) {
	a := []int{1, 2, 3, 4, 5}
	b := *(*[]MyInt)(unsafe.Pointer(&a))
	t.Log(b)
}

// 原子类型操作
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()
}

相关推荐

  1. Go语言学习12-反射Unsafe

    2024-03-20 09:04:05       47 阅读
  2. go语言利用反射实现reverse函数

    2024-03-20 09:04:05       55 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-20 09:04:05       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-20 09:04:05       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-20 09:04:05       87 阅读
  4. Python语言-面向对象

    2024-03-20 09:04:05       96 阅读

热门阅读

  1. go 解决货币计算的难题:避免浮点数陷阱

    2024-03-20 09:04:05       31 阅读
  2. Rust 的 PhantomData

    2024-03-20 09:04:05       42 阅读
  3. ES进程除了kill之外,有什么优雅关闭的方式吗?

    2024-03-20 09:04:05       43 阅读
  4. R语言Scale函数与normalize.quantiles()函数的异同

    2024-03-20 09:04:05       46 阅读
  5. Linux Shell 管道基本介绍

    2024-03-20 09:04:05       44 阅读
  6. 红魔馆的馆主

    2024-03-20 09:04:05       39 阅读
  7. SQL-存储过程介绍

    2024-03-20 09:04:05       48 阅读
  8. 未来之路:Python PDF处理技术的革新

    2024-03-20 09:04:05       44 阅读
  9. 使用 pypdf 快速切分 PDF 文件

    2024-03-20 09:04:05       47 阅读
  10. 信息学奥赛之C++中的数据类型数据结构

    2024-03-20 09:04:05       47 阅读