欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RTMP协议视频直播点播平台EasyDSS内Go语言使用反射优化代码技巧说明

程序员文章站 2022-07-08 18:23:30
...

在开发 EasyDSS 项目中,随着功能的扩大,慢慢的发现有很多类似的代码存在于代码中。因为结构体的不同,使用相同的函数进行合并非常困难,使用反射就可以将这些代码合并。

RTMP协议视频直播点播平台EasyDSS内Go语言使用反射优化代码技巧说明

代码量越少,出现 bug 的概率则越低,因此对于相似的函数最好进行合并,用来降低代码量。以下文章中介绍如何使用反射来将部分代码合并的技巧。

首先需要了解什么是反射。在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。但在 Go 语言中并未完全实现反射的所有功能, Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制。

以下代码为判断一个用户为id的数据在数据库中是否存在的功能。

func (impl *BaseDaoImpl) Exists0(id string) error {
   data := table.User{}
   return impl.fromTable().First(&data, impl.WherePrimaryKey, id).Error
}

判断日志是否存在的功能

func (impl *BaseDaoImpl) Exists1(id string) error {
   data := table.ActiveLog{}
   return impl.fromTable().First(&data, impl.WherePrimaryKey, id).Error
}

判断产品是否存在的功能

func (impl *BaseDaoImpl) Exists3(id string) error {
   data := table.Product{}
   return impl.fromTable().First(&data, impl.WherePrimaryKey, id).Error
}

由以上代码就可以看出,三者完全一致,仅仅是 data 的类型不同。如果项目中此种代码比较少的话,没什么问题,但是随着功能的渐渐增多,此种代码就越来越多,代码冗余了,因此可以把三个代码进行合并成一个。

func (impl *BaseDaoImpl) Exists4(data interface{}, id string) error {
   return impl.fromTable().First(data, impl.WherePrimaryKey, id).Error
}

interface{} 为任意类型的结构体。

调用方法如下:
impl.Exists4(&table.User{}, id)
impl.Exists4(&table.ActiveLog{}, id)
impl.Exists4(&table.Product{}, id)

该种修改方式,降低了代码的冗余量,但是需要将函数的参数进行修改,增加一个 interface{} 任意类型的参数,并且在每次进行函数调用时,都需要将对应的结构体传入进入,因此还可以使用反射进行优化。

经过反射优化后的代码如下:

func (impl *BaseDaoImpl) Exists(id string) error {
   dataType := reflect.TypeOf(impl.TableStruct)
   data := reflect.New(dataType)
   return impl.fromTable().First(&data, impl.WherePrimaryKey, id).Error
}

impl.TableStruct 为 BaseDaoImpl 初始化的时候传入进来的结构体对象。在代码运行过程中,如果直接使用该对象,该对象内部的数据就会被改变,上一次的数据有可能影响这一次数据的查询。比如 TableStruct 为 user,开始 user.ID = 100, user.Name = “sam”,等到下一次使用该对象时,需要重新赋值。如果不重新赋值,则会出现以下情况。比如查询 id 为 200 的数据,采用 gorm 框架查询数据,最终发送的数据库语句就为select * where (user.id = 100) and id = 200 from users
就是查询 id 为 100,并且 id 为 200 的数据,显然此种数据是不存在的。因此每次查询前重新建一个内存数据查询就不会影响查询结果。

reflect 包就是 Go 语言中的反射包,其中reflect.TypeOf(impl.TableStruct) 就是查看传递进来的实例对象的数据类型,然后知道类型后,就调用 reflect.New(dataType) 就在内存中新建了一个新的对象,操作该未被使用过的对象,查询结果就会正确。

使用反射的方法,不用修改原先函数的参数,也消除了重复代码的存在,但是因为经过了一层反射,所以速度肯定没有Exists4函数快速,但是一般情况下,该段的速度消耗不需要考虑,因为推荐经过使用反射优化重复代码,简化代码,降低代码 bug 率。

RTMP协议视频直播点播平台EasyDSS内Go语言使用反射优化代码技巧说明

本文是基于EasyDSS的开发过程给大家做个简单的说明科普,EasyDSS的开发过程复杂,可以用于各种不同场景的视频监控系统搭建,并且支持H265编码视频的播放,欢迎大家来进行测试使用。