反思:从类型创建对象-第一部分(原始类型)

这是一个分为2部分的博客系列文章的第1部分,该系列文章涉及Golang中的根据类型创建对象。 本部分讨论原始类型的创建。

Golang Gopher

Golang中的reflect包提供了必要的API,可根据要处理的对象的类型来更改程序的控制流。

反射包提供两个重要的结构TypeValue

Type是任何Go类型的表示。 即它可以用于编码任何Go类型(例如intstringboolmyCustomType等)。 Value表示任何Go值。 即它可以用于编码和操纵任何Go值。

类型与种类

Golang具有区分typekind的隐藏的,鲜为人知的约定。 可以通过示例来理解区别。 考虑以下结构:

 输入示例struct { 
field1 type1
field2 type2
}

该结构的对象type将是example 。 该对象的kindstruct 。 可以将kind视为typetype

Golang中的所有结构都属于同一kind ,但type

诸如PointerArraySliceMap等复合类型在typekind之间进行了区分。

相反,诸如intfloatstring等原始类型不会区分kindtype 。 即,一个int变量的类型是int 。 一个int变量的type也是int

从类型创建对象

为了从类型签名创建对象,对象的typekind都是必需的。 此后,当我使用“类型签名”一词时,是指该语言的reflect.Typereflect.Type对象。

从原始类型创建原始对象

原始对象可以使用其零值从其类型签名中创建。

类型的零值是该类型的未初始化对象的值

这是Golang中所有原始类型的列表

 布尔 
整数
诠释8
16位
32位
整数64
维特
Uint8
Uint16
Uint32
Uint64
Uintptr
浮点32
浮动64
复杂64
复杂128

不安全指针

使用reflect.Zero函数,可以创建基本类型的对象

  func CreatePrimitiveObjects(t Reflection.Type)Reflection.Value { 
返回reflect.Zero(t)
}

这将创建所需类型的对象,并返回与基础零值相对应的reflect.Value对象。 为了使用该对象,需要提取其值。

可以使用适合每种原始类型的方法来提取对象的值。

提取整数值

Golang中有5种Integer类型:

 整数 
诠释8
16位
32位
整数64

整数类型表示平台定义的默认大小的整数。 接下来的4种类型分别是大小(以位为单位)为8、16、32和64的整数。

为了提取每种Integer类型,需要将代表Integer的reflect.Value对象转换为适当的类型。

这是应如何提取int32

  //提取Int32 
func extractInt32(vreflect.Value)(int32,错误){
如果reflect.Kind()!= reflect.Int32 {
返回int32(0),errors.New(“无效输入”)
}
var intVal int64
intVal = v.Int()
返回int32(intVal),nil
}

请务必注意, reflect.Int()始终返回int64 。 这是因为int64可以对其中的所有其他Integer类型进行编码。

以下是应提取其余所有Integer类型的方法:

  //提取Int64 
func extractInt64(vreflect.Value)(int64,错误){
如果reflect.Kind()!= reflect.Int64 {
返回int64(0),errors.New(“无效输入”)
}
var intVal int64
intVal = v.Int()
返回intVal,无
}
//提取Int16
func extractInt16(vreflect.Value)(int16,错误){
如果reflect.Kind()!= reflect.Int16 {
返回int16(0),errors.New(“无效输入”)
}
var intVal int64
intVal = v.Int()
返回int16(intVal),nil
}
//提取Int8
func extractInt8(vreflect.Value)(int8,错误){
如果reflect.Kind()!= reflect.Int8 {
返回int8(0),errors.New(“无效输入”)
}
var intVal int64
intVal = v.Int()
返回int8(intVal),nil
}
//提取Int
func extractInt(vreflect.Value)(int,错误){
如果reflect.Kind()!= reflect.Int {
返回int(0),errors.New(“无效输入”)
}
var intVal int64
intVal = v.Int()
返回int(intVal),nil
}

提取布尔值

布尔值由反射包中的常量Bool表示。

可以使用Bool()方法从reflect.Value对象中提取它们:

  //提取布尔 
func extractBool(vreflect.Value)(布尔值,错误){
如果reflect.Kind()!= reflect.Bool {
返回false,errors.New(“无效输入”)
}
返回v.Bool(),无
}

提取无符号整数

Golang中有5种无符号整数类型:

 维特 
Uint8
Uint16
Uint32
Uint64

Uint类型表示平台定义的默认大小的无符号整数。 接下来的4种类型分别是大小(以位为单位)为8、16、32和64的无符号整数。

为了提取每种Unsigned Integer类型,需要将代表Unsigned Integer的reflect.Value对象转换为适当的类型。

提取Uint32方法如下:

  //提取Uint32 
func extractUint32(vreflect.Value)(uint32,错误){
如果reflect.Kind()!= reflect.Uint32 {
返回uint32(0),errors.New(“无效输入”)
}
var uintVal uint64
uintVal = v.Uint()
返回uint32(uintVal),nil
}

请务必注意, reflect.Uint()始终返回uint64 。 这是因为uint64可以对其中的所有其他Integer类型进行编码。

这是应提取其余无符号整数类型的方式

  //提取Uint64 
func extractUint64(vreflect.Value)(uint64,错误){
如果reflect.Kind()!= reflect.Uint64 {
返回uint64(0),errors.New(“无效输入”)
}
var uintVal uint64
uintVal = v.Uint()
返回uintVal,无
}
//提取Uint16
func extractUint16(vreflect.Value)(uint16,错误){
如果reflect.Kind()!= reflect.Uint16 {
返回uint16(0),errors.New(“无效输入”)
}
var uintVal uint64
uintVal = v.Uint()
返回uint16(uintVal),nil
}
//提取Uint8
func extractUint8(vreflect.Value)(uint8,错误){
如果reflect.Kind()!= reflect.Uint8 {
返回uint8(0),errors.New(“无效输入”)
}
var uintVal uint64
uintVal = v.Uint()
返回uint8(uintVal),nil
}
//提取Uint
func extractUint(vreflect.Value)(uint,错误){
如果reflect.Kind()!= reflect.Uint {
返回uint(0),errors.New(“无效输入”)
}
var uintVal uint64
uintVal = v.Uint()
返回uint(uintVal),无
}

提取浮点数

Golang中有2种浮点数类型:

 浮点32 
浮动64

Float32类型表示大小为32位的浮点数。 Float64类型表示大小为64位的浮点数。

为了提取每种浮点数类型,需要将表示浮点数的reflect.Value对象转换为适当的类型。

提取Float32方法如下:

  //提取Float32 
func extractFloat32(vreflect.Value)(float32,错误){
如果reflect.Kind()!= reflect.Float32 {
返回float32(0),errors.New(“无效输入”)
}
var floatVal float64
floatVal = v.Float()
返回float32(floatVal),nil
}

请务必注意, reflect.Float()始终返回float64 。 这是因为float64可以对其中的所有其他浮点数类型进行编码。

这是应如何提取64位浮点数值的方法

  //提取Float64 
func extractFloat64(vreflect.Value)(float64,错误){
如果reflect.Kind()!= reflect.Float64 {
返回float64(0),errors.New(“无效输入”)
}
var floatVal float64
floatVal = v.Float()
返回floatVal,nil
}

提取复杂值

Golang有2种复杂类型:

 复杂64 
复杂128

Complex64类型表示大小为Complex64复数。 Complex128类型表示大小为128位的复数。

为了提取每种Complex类型,需要将表示Complex值的reflect.Value对象转换为适当的类型。

这是应提取Complex64方法:

  //提取Complex64 
func extractComplex64(vreflect.Value)(complex64,错误){
如果reflect.Kind()!= reflect.Complex64 {
返回complex64(0),errors.New(“无效输入”)
}
var complexVal complex128
complexVal = v.Complex()
返回complex64(complexVal),无
}

请务必注意, reflect.Complex()始终返回complex128 。 这是因为complex128可以对其中的所有其他Complex类型进行编码。

这是应如何提取128位Complex值的方法

  //提取Complex128 
func extractComplex128(vreflect.Value)(complex128,错误){
如果reflect.Kind()!= reflect.Complex128 {
返回complex128(0),errors.New(“无效输入”)
}
var complexVal complex128
complexVal = v.Complex()
返回complexVal,无
}

提取字符串值

字符串值由反射包中的常量String表示。

可以使用对象的String()方法从reflect.Value对象中提取它们。

提取String方法如下:

  //提取字符串 
func extractString(vreflect.Value)(字符串,错误){
如果reflect.Kind()!= reflect.String {
返回“”,errors.New(“无效输入”)
}
返回v.String(),无
}

提取指针值

Golang中有2种Pointer类型:

  Uintptr 
不安全指针

UintptrUnsafePointer只是表示过程内存中虚拟地址的uint值。 它可以表示变量或函数的位置。

UintptrUnsafePointer之间的区别在于, Uintptr由Go运行时进行类型检查,而UnsafePointer没有。 UnsafePointer的内存布局兼容,则可用于将任何Go类型转换为任何其他Go类型。 如果您想探索这个问题,请在下面评论,我将在上面写更多。

可以分别使用Addr()方法和UnsafeAddr()方法从reflect.Value对象中提取reflect.ValueUnsafeAddr() 。 这是显示应如何提取Uintptr的示例

 应该以这种方式提取Uintptr //提取Uintptr 
func extractUintptr(vreflect.Value)(uintptr,错误){
如果reflect.Kind()!= reflect.Uintptr {
返回uintptr(0),errors.New(“无效输入”)
}
var ptrVal uintptr
ptrVal = v.Addr()
返回ptrVal,nil
}

这是应提取UnsafePointer值的方式

  //提取UnsafePointer 
func extractUnsafePointer(vreflect.Value)(unsafe.Pointer,错误){
如果reflect.Kind()!= reflect.UnsafePointer {
返回unsafe.Pointer(0),errors.New(“无效输入”)
}
var unsafeVal unsafe.Pointer
unsafeVal = unsafe.Pointer(v.UnsafeAddr())
返回unsafeVal,无
}

重要的是要注意上面的v.UnsafeAddr()返回一个uintptr值。 它应该在同一行中进行类型转换,否则unsafe.Pointer值可能未指向预期的位置。

请注意,应在不检查kind情况下使用reflect.Value结构的任何方法,因为它很容易引起panic

在下一篇博客文章中,我将写有关创建更复杂的类型(如structpointerchanmapslicearray等)的文章。 敬请关注!