Go 语言的反射是一种在运行时动态访问程序元数据的能力。反射可以让我们在运行时检查类型和变量,例如它的大小、方法和动态的值等。这种机制让我们可以编写更加通用的函数和类型,而不需要关心具体的类型。
//随机给proto协议对象赋值
func randMsg() (int32, proto.Message) {
var msgId int32
if common.Random(0, 4) == 0 {
//25%的概率发送ack or ntf协议
var msgIds []int32
for id, name := range pb_server.MessageID_name {
if strings.Contains(name, "ACK") || strings.Contains(name, "NTF") {
msgIds = append(msgIds, id)
}
}
msgId = msgIds[common.Random(0, len(msgIds))]
} else {
//75%的概率发送req协议
var msgIds []int32
for id, name := range pb_server.MessageID_name {
if strings.Contains(name, "REQ") {
msgIds = append(msgIds, id)
}
}
msgId = msgIds[common.Random(0, len(msgIds))]
}
//msgId = 1064 //slice test
//msgId = 1111 //map test
proname := "server." + common.ProtoMsgTrans(pb_server.MessageID_name[msgId])
obj, err := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(proname))
if err != nil {
l4g.Debug("RandMsgEvent name:%s err:%v", proname, err)
return 0, nil
}
msg := proto.MessageV1(obj.New())
l4g.Debug("RandMsgEvent name:%s", proname)
// 获取 Message 的反射类型和值
msgType := reflect.TypeOf(msg).Elem()
msgValue := reflect.ValueOf(msg).Elem()
foreachField(msgType, &msgValue)
return msgId, msg
}
func foreachField(tp reflect.Type, value *reflect.Value) {
for i := 0; i < tp.NumField(); i++ {
field := tp.Field(i)
if strings.HasPrefix(field.Name, "XXX_") {
continue
}
//l4g.Debug("forechField i:%d name:%s type:%v", i, field.Name, field.Type.Kind().String())
fieldValue := value.Field(i)
setValue(&field, &fieldValue)
}
}
func setValue(field *reflect.StructField, value *reflect.Value) {
switch field.Type.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
{
var tmp int64
switch field.Type.Kind() {
case reflect.Int:
tmp = int64(math.MaxInt)
case reflect.Int8:
tmp = int64(math.MaxInt8)
case reflect.Int16:
tmp = int64(math.MaxInt16)
case reflect.Int32:
tmp = int64(math.MaxInt32)
case reflect.Int64:
tmp = int64(math.MaxInt64)
}
rand := common.Random(0, 3)
if rand == 0 {
value.SetInt(int64(0))
} else if rand == 1 {
value.SetInt(int64(common.Random(0, int(tmp))))
} else {
value.SetInt(tmp)
}
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
{
var tmp uint64
switch field.Type.Kind() {
case reflect.Uint:
tmp = uint64(math.MaxUint)
case reflect.Uint8:
tmp = uint64(math.MaxUint8)
case reflect.Uint16:
tmp = uint64(math.MaxUint16)
case reflect.Uint32:
tmp = uint64(math.MaxUint32)
case reflect.Uint64:
tmp = uint64(math.MaxUint64)
}
rand := common.Random(0, 3)
if rand == 0 {
value.SetUint(uint64(0))
} else if rand == 1 {
value.SetUint(uint64(common.Random(0, int(tmp)))) //tmp越界忽略
} else {
value.SetUint(tmp)
}
}
case reflect.String:
{
value.SetString("hello world!!!")
}
case reflect.Float32, reflect.Float64:
{
value.SetFloat(float64(common.Random(0, 100)))
}
case reflect.Bool:
{
value.SetBool(common.Random(0, 2) == 0)
}
case reflect.Ptr:
{
newType := field.Type.Elem()
newVal := reflect.New(newType).Elem()
foreachField(newType, &newVal)
value.Set(newVal.Addr())
}
case reflect.Struct:
//proto生成的代码结构都是指针,无需实现
case reflect.Slice:
{
sliceType := field.Type
sliceLen := common.Random(1, 6) // 随机生成长度为 1 到 5 的切片
newSlice := reflect.MakeSlice(sliceType, sliceLen, sliceLen)
elemType := sliceType.Elem()
for i := 0; i < sliceLen; i++ {
elem := newSlice.Index(i)
if elem.Type().Kind() == reflect.Ptr {
newElem := reflect.New(elem.Type().Elem()).Elem()
foreachField(elemType.Elem(), &newElem)
elem.Set(newElem.Addr())
} else {
elemField := &reflect.StructField{
Name: field.Name,
PkgPath: field.PkgPath,
Type: elemType,
Tag: field.Tag,
Offset: field.Offset,
Index: field.Index,
Anonymous: field.Anonymous,
}
setValue(elemField, &elem)
}
newSlice.Index(i).Set(elem)
}
value.Set(newSlice)
}
case reflect.Map:
{
mapType := field.Type
mapLen := common.Random(1, 6) // 随机生成长度为 1 到 5 的映射
newMap := reflect.MakeMapWithSize(mapType, mapLen)
keyType := mapType.Key()
elemType := mapType.Elem()
fmt.Println("map type:", mapType.Kind(), "elemType:", elemType.Kind())
for i := 0; i < mapLen; i++ {
//key
newKey := reflect.New(keyType).Elem()
keyField := reflect.StructField{
Name: field.Name + "_key",
PkgPath: field.PkgPath,
Type: keyType,
Tag: field.Tag,
Offset: field.Offset,
Index: field.Index,
Anonymous: field.Anonymous,
}
setValue(&keyField, &newKey)
//value
newElem := reflect.New(elemType).Elem()
//fmt.Println("newElem kind:", newElem.Kind(), "typename:", newElem.Type().Name())
if elemType.Kind() == reflect.Ptr {
tmpElem := reflect.New(newElem.Type().Elem()).Elem()
foreachField(elemType.Elem(), &tmpElem)
newElem.Set(tmpElem.Addr())
} else if elemType.Kind() == reflect.Struct {
foreachField(elemType, &newElem)
} else {
elemField := reflect.StructField{
Name: field.Name + "_value",
PkgPath: field.PkgPath,
Type: elemType,
Tag: field.Tag,
Offset: field.Offset,
Index: field.Index,
Anonymous: field.Anonymous,
}
setValue(&elemField, &newElem)
}
newMap.SetMapIndex(newKey, newElem)
}
value.Set(newMap)
}
default:
{
l4g.Error("setFieldValue unkown kind:%v name:%s", field.Type.Kind(), field.Name)
}
}
}