• go基于泛型实现继承


    概述

    在某些情况下,我们需要继承的时候父类的函数和方法能够影响(或使用)子类的一些数据,这并不符合一般情况下的类原则,但是很有用。
    在go里面,我们通过组合实现继承,但是组合的类没办法操作同级别的类,解决方案是把操作方法提出来作为函数进行处理。
    对于有些情况下,明明是紧密耦合的函数,却不得不拆出来单独使用,还是让人很不爽。
    好在go的泛型能够解决这个问题。
    下面是我基于go泛型实现的一个动态结构体,包含一些固定的基本字段以及一些动态字段。在某些需要直接从请求参数获取字段名并赋值的需求的时候,这个操作很有用。特别是一个结构体几十个字段的时候:

    package models
    
    import (
    	"encoding/json"
    	"reflect"
    	"regexp"
    )
    
    
    type Info[T any] struct {
    	T   T //固定字段,对于一般情况下会本身会读取到的字段写入这里
    	Ext map[string]interface{} // 其它扩展数据,根据需要添加,key/value形式获取
    }
    
    func NewInfo[T any]() Info[T] { // 主要是为了初始化map
    	res := Info[T]{}
    	res.Ext = map[string]interface{}{}
    	return res
    }
    func (s Info[T]) MarshalJSON() ([]byte, error) { // 将动态字段和静态字段组合放到一个结构体
    	marshal, err := json.Marshal(s.T)
    	if err != nil {
    		return nil, err
    	}
    	if len(s.Ext) != 0 {
    		extMarshal, err := json.Marshal(s.Ext)
    		if err != nil {
    			return nil, err
    		}
    		marshal = append(marshal[0:len(marshal)-1], []byte(`,"__ext__":{},`)...)
    		marshal = append(marshal, extMarshal[1:]...)
    	}
    	return marshal, nil
    }
    func (s *Info[T]) UnmarshalJSON(data []byte) error { // 反序列化
    	dataS := string(data)
    	subInfo := regexp.MustCompile(`,"__ext__":{},`).Split(dataS, 2)
    	if len(subInfo) == 1 { //未找到对象
    		return json.Unmarshal(data, &s.T)
    	} else {
    		baseStr := subInfo[0] + "}"
    		extStr := "{" + subInfo[1]
    		err := json.Unmarshal([]byte(baseStr), &s.T)
    		if err != nil {
    			return err
    		}
    		ext := map[string]interface{}{}
    		err = json.Unmarshal([]byte(extStr), &ext)
    		if err != nil {
    			return err
    		}
    		s.Ext = ext
    		return nil
    	}
    }
    
    func (s Info[T]) GetAttr(fieldName string) (v interface{}, find bool) { // 根据字符串获取值,这里甚至可以改造为忽略大小写
    	refval := reflect.ValueOf(s)
    	val := refval.FieldByName(fieldName)
    	if val.IsValid() {
    		return val.Interface(), true
    	}
    	dynamicStruct, ok := s.Ext[fieldName]
    	return dynamicStruct, ok
    }
    
    func (s *Info[T]) SetAttr(fieldName string, value interface{}) bool { //根据字符串写入值,这里也可以忽略大小写
    	refval := reflect.ValueOf(s).Elem()
    	val := refval.FieldByName(fieldName)
    	if val.IsValid() {
    		val.Set(reflect.ValueOf(value))
    		return true
    	}
    	s.Ext[fieldName] = value
    	return false
    }
    
    • 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
    • 73
    • 74
    • 75
    • 76
  • 相关阅读:
    Verilog中parameter在仿真时的应用
    【考研】串的模式匹配算法——KMP算法(含真题)
    DC综合基本概念:uniquify
    鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统
    35. 搜索插入位置 --力扣 --JAVA
    ASEMI整流桥KBL406参数,KBL406图片
    额温枪(红外线测温仪)方案产品用途和原理
    卡方检验简介
    从事前端真的没有后端工资高?
    XML的解析
  • 原文地址:https://blog.csdn.net/weixin_36179862/article/details/126030485