当前位置: 首页 > news >正文

范文网站学校技防 物防建设运维是做什么的

范文网站学校技防 物防建设,运维是做什么的,wordpress修改源代码,软装设计费收费标准一. 匿名字段 go支持只提供类型而不写字段名的方式#xff0c;也就是匿名字段#xff0c;也称为嵌入字段。 同名字段的情况 所以自定义类型和内置类型都可以作为匿名字段使用 指针类型匿名字段 二.接口 接口定义了一个对象的行为规范#xff0c;但是定义规范不实现#xff…一. 匿名字段 go支持只提供类型而不写字段名的方式也就是匿名字段也称为嵌入字段。 同名字段的情况 所以自定义类型和内置类型都可以作为匿名字段使用 指针类型匿名字段 二.接口 接口定义了一个对象的行为规范但是定义规范不实现由具体的对象实现规范的细节。 2.1 接口类型 在Go语言中接口(interface)是一种类型一种抽象类型。 interface是一组method的集合接口做的事情就像定义一个协议不关心属性(数据)只关心行为(方法)。 2.2 为什么使用接口 查看下面的图片只是由于类型不同就需要定义两个逻辑一样的函数。如果后面出现了其它动物也会需要定义函数。 Go语言为了解决类似上面的问题就设计了接口这个概念。接口区别于我们之前所有的具体类型接口是一个抽象类型。当你看到一个接口类型是你不知道他是什么唯一知道的是通过它的方法能做什么。  2.3 接口定义 Go语言提倡面向接口编程。 接口在底层实现上包含两部分即类型(type)和数据(data)。接口是一个或多个方法签名的集合任何类型的方法集中只要拥有该接口对应的全部方法就表示它实现了该接口无须在该类型上显示声明实现了那个接口。这称为Structural Typing。所谓对应方法是指有相同名称参数列表(不包括参数名)以及返回值。当然该类型还可以有其它方法。接口只有方法声明没有实现没有数据字段(属性)。接口可以匿名嵌入其它接口或者嵌入到其它结构中。对象赋值给接口时会发生拷贝而接口内部存储的是指向这个复制品的指针即无法修改复制品的状态也无法获取指针。即如果对象是结构体或者基本数据类型它会被值拷贝到接口中。如果对象是指针类型这个指针指向的结构体实现了接口那么接口中存储的是指针的副本而不是指针本身。只有当接口存储的类型和对象都为nil时接口才为nil。接口调用不会做receiver的自动转换。接口同样支持匿名字段方法。接口可以实现类似面向对象编程(OOP)的多态。空接口可以作为任何类型数据的容器。空接口是没有声明任何方法的接口。但是也无法通过空接口来调用对象的方法或访问其属性。一个类型可以实现多个接口。接口命名习惯以er结尾。 每一个接口由数个方法组成接口的定义格式如下 type 接口类型名 interface{方法1参数列表1返回值列表1方法2参数列表2返回值列表2... } 其中 接口名使用type将接口名定义为自定义的类型名。Go语言的接口在命名时一般会在单词后面添加er接口名最好要能突出该接口的类型含义。方法名当方法名首字母是大写且接口类型名首字母也是大写时这个方法可以被接口所在的包(package)之外的代码访问。参数列表和返回值列表参数列表和返回值列表中的参数变量名可以省略。 举个例子 type writer interface{Write([]byte) error } 当看到这个接口的时候你不知道他是什么唯一知道的是可以通过它的Write方法来做一些事情。 2.4 实现接口的条件 一个对象只要全部实现了接口的方法那么就实现了这个接口。换句话说接口就是一个需要实现的方法列表。 package mainimport fmttype Sayer interface {Say() }type Cat struct{}//实现了Sayer接口 func (c *Cat) Say() {fmt.Println(喵喵喵...) }type Dog struct{}//实现了Sayer接口 func (d *Dog) Say() {fmt.Println(汪汪汪...) } 2.5 接口类型变量 接口类型变量能够存储所有实现了该接口的实例。 需要指针传入是因为方法的receiver为指针类型对象的指针类型(*T)的方法集为值类型(T)和指针类型(*T)。 2.6 值接收者和指针接收者实现接口的区别 值接收者和指针接收者实现接口区别在于方法集的不同。接口接收值类型(T)对象方法集为值接收者(T)实现的方法。接口接收指针类型对象(*T)方法集为值接收者(T)和指针接收者(*T)现象的方法。 值接收者 指针接收者 2.7 类型与接口的关系 2.7.1 一个类型实现多个接口 一个类型可以同时实现多个接口而接口间彼此独立不知道对方的实现。 2.7.2 多个类型实现同一个接口 Go语言中不同的类型还可以实现同一接口。 一个接口的方法不一定需要由一个类型完全实现接口的方法可以通过在类型中嵌入其它类型或者结构体来实现。 2.7.3 接口嵌套 接口与接口之间可以通过嵌套创造出新的接口。 type Sayer interface {Say() }type Mover interface {Move() }type Animal interface {SayerMover } 嵌套的接口的使用和普通接口一样这里实现嵌套的接口。 2.8 空接口 2.8.1 空接口的定义 空接口是指没有定义任何方法的接口。因此任何类型都实现了空接口。 空接口类型变量可以存储任意类型的变量。 2.8.2 空接口的应用 空接口作为函数参数 使用空接口实现可以接收任意类型的函数参数。 空接口作为map的值 使用空接口实现可以保存任意值的字典。 2.8.3 类型断言 空接口可以存储任意类型的值那我们如何获取其存储的具体数据呢 接口值 一个接口的值(简称接口值)是由一个具体类型和具体类型的值俩个部分组成。这两部分分别称为接口的动态类型和动态值。 我们来看一个例子 package mainimport (bytesioos )func main() {var w io.Writerw os.Stdoutw new(bytes.Buffer)w nil } 图解  想要判断空接口中的值这个时候就可以使用类型断言其语法格式 x.(T) 其中 x表示类型为interface{}的变量T 表示断言x可能是的类型 该语法返回两个参数第一个参数是x转化为T类型后的变量第二个是布尔值若为true表示断言成功为false则表示断言失败。 举个例子 自定义类型  我们还可以使用switch语句来实现多个类型的断言 因为空接口可以存储任意类型值的特点所以空接口在Go语言中使用十分广泛。 但是接口需要注意的是只有当有两个或者两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。不要为了接口而写接口那样会增加不必要的抽象导致不必要的运行时消耗。 三. 接口的底层实现 案例 package maintype EInterface interface{} type IInterface interface {Do() }type IInterfaceImpl struct{}func (imp1 IInterfaceImpl) Do() {}func main() {var impl1 EInterface IInterfaceImpl{}var impl2 IInterface IInterfaceImpl{}println(impl1)println(impl2) } 3.1 数据结构 golang中的接口非为带方法的接口和不带方法的空接口带方法的接口在底层使用iface表示空接口的底层则是eface表示。 eface eface是空接口类型的底层实现源码如下 type eface struct {_type *_typedata unsafe.Pointer } 两个字段都是指针类型含义分别是 _type指向实际的类型。上面案例是IInterfaceImpldata指向实际的值。上面案例是IInterfaceImpl结构体的值         注意var v interface{} (*int)nil变量v其实使用的eface结构表示。其中_type的类型对应的是int类型的指针而data部分为nil所以整体变量v ! nil。  iface iface是非空接口类型的底层实现源码如下 type iface struct {tab *itabdata unsafe.Pointer } 上面的案例impl2就是非空接口类型的变量两个字段也是指针类型含义分别是 tab指向itab结构体itab结构体存储了接口所有方法列表。data指向对应的值。上面案例为IInterfaceImpl结构体的值。  _type结构 该结构于golang的类型系统有关无论是内置类型还是自定义数据类型都用_type结构表示其元信息。 type _type struct {size uintptrptrdata uintptr // size of memory prefix holding all pointershash uint32tflag tflagalign uint8fieldAlign uint8kind uint8// function for comparing objects of this type// (ptr to object A, ptr to object B) - ?equal func(unsafe.Pointer, unsafe.Pointer) bool// gcdata stores the GC type data for the garbage collector.// If the KindGCProg bit is set in kind, gcdata is a GC program.// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.gcdata *bytestr nameOffptrToThis typeOff } 以int32类型的指针为例具体的字段含义及其作用如下 size类型的大小(字节数)。*int32类型的大小是64位系统下8字节32位系统下4字节。ptrdata所有指针内存前缀大小指向int32类型的实例。hash类型的哈希值即_type.hash。tflag类型标记表示类型的特性。align类型的对齐方式*int32类型32位系统下按4字节对齐64位系统下8字节对齐。fieldAlign字段对齐方式*int32类型的字段对齐方式 32位系统下按4字节对齐64位系统下8字节对齐。kind类型的种类。用于区分基本类型结构体接口等。equal比较函数用于区分两个*int32类型的实例是否相等。gcdata与GC有关。str类型名称的偏移。ptrToThis指向该类型的指针。 _type是一个很复杂的结构这里只需要知道通过该结构能获取到结构体实现的所有方法。 下面是iface.go中的init方法中的一段代码_type结构的uncommon方法会返回一个指针在此基础上加一个偏移量(moff)就能得到实际结构体实现的方法列表。 func (m *itab) init() string {inter : m.intertyp : m._typex : typ.uncommon()// both inter and typ have method sorted by name,// and interface names are unique,// so can iterate over both in lock step;// the loop is O(nint) not O(ni*nt).ni : len(inter.mhdr)nt : int(x.mcount)// 实际类型的方法数组xmhdr : (*[1 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt]... } itab结构 itab结构是golang非空接口iface中一个非常重要的字段类型的赋值断言等都离不开该字段。 type itab struct {// 接口类型的指针比如对于 io.Reader 接口记录的是接口类型的信息(如接口定义的方法Read 方法)inter *interfacetype// 实际结构类型的指针记录的是实际类型的信息比如 os.File 类型实现了 io.Reader 接口_type *_typehash uint32 // copy of _type.hash. Used for type switches._ [4]byte// 变长数组fun[0]0 表示 _type 没有实现 inter 接口fun [1]uintptr }type interfacetype struct {// 接口类型元信息typ _type// 包路径pkgpath name// 接口的所有方法列表mhdr []imethod } itab结构的字段含义 inter记录的是非空接口类型的元信息其中mhdr是接口的方法表_type记录的是实际类型的指针即实现接口的类型fun保存的是实际类型中实现的方法的地址。当fun[0] 0时表示该类型没有实现该接口当fun[0]!0时则代表该类型实现了接口的所有方法这时候就可以通过偏移量调用具体类型对象的方法。 3.2 itab关键方法 通过上述对itab结构的描述不难理解itab其实就是一个缓存用于快速判断具体类型是否实现了某个接口。 一般情况下如果要判断需要对接口的具体类型的方法集进行比较。当如果每次都这样比较效率会很低。通过将比较结果缓存起来下次再判断的时候就能直接根据itab快速得出结论了。 go源码的runtime里定义了全局变量itebTable用户缓存itab。 // 用于缓存 itab itabTable itabTableInit itabTableInit itabTableType{size: itabInitSize}// 全局的 itab 表 type itabTableType struct {size uintptr // entries 的长度count uintptr // 当前 entries 的数量即 itab 数量entries [itabInitSize]*itab // 保存 itab 的哈希表 } 这里其实是一个全局的哈希表哈希表的key就是interfacetype _typevalue就是对应的itab。 判断某个类型是否实现了接口时只需要传入接口的接口类型interfacetype和实际类型_type即可 如果在itabTable中没有找到对应的itab则需要依次比较方法集生成itab并缓存到itabTable中如果找到了对应的itab则判断func[0]如果等于0则说明该类型没有实现该接口  有了哈希表还要考虑如何向其中添加数据和获取数据也就是下面两个方法。 getitab 该函数的作用是通过interfacetype和_type也就是接口类型和实际结构类型从表中获取对应itab。 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {...var m *itab// 尝试从 itabTable 表中获取 itab获取到直接返回t : (*itabTableType)(atomic.Loadp(unsafe.Pointer(itabTable)))if m t.find(inter, typ); m ! nil {goto finish}// 没有找到获取锁再次查找lock(itabLock)if m itabTable.find(inter, typ); m ! nil {unlock(itabLock)goto finish}// 如果 itabTable 中没有找到则新建一个 itab并调用 itabAdd 将其缓存到 itabTable 中m (*itab)(persistentalloc(unsafe.Sizeof(itab{})uintptr(len(inter.mhdr)-1)*goarch.PtrSize, 0, memstats.other_sys))m.inter interm._type typm.hash 0m.init()itabAdd(m)unlock(itabLock) finish:// m.fun[0] ! 0 表示该类型实现了接口的所有方法可以返回 itabif m.fun[0] ! 0 {return m}//canfail 用于控制类型转换失败的行为。比如 v : s.(Dst)这里的 canfail false那么在断言失败时会 panicif canfail {return nil}panic(TypeAssertionError{concrete: typ, asserted: inter.typ, missingMethod: m.init()}) } 这里主要的逻辑是 更具interfacetype和_type尝试从itabTable中获取itab如果itabTable没有找到itab则新创建一个itab并将其缓存到itabTable中判断该类型是否实现了接口的所有方法(m.fun[0]!0)如果该类型没有实现接口的所有方法则根据canfail判断是否paniccanfail为false则会panic。比如类型断言时如果不接受第二个返回值则断言失败会panic 首次调用getitab方法获取时哈希表中是没有对应数据的。此时不仅要创建itab结构还要对其涉及到的接口和类型的方法集进行判断初始化等。相关代码在init中。 func (m *itab) init() string {inter : m.intertyp : m._typex : typ.uncommon()// 接口定义的方法数量ni : len(inter.mhdr)// 实际类型的方法数量nt : int(x.mcount)// 实际类型的方法数组xmhdr : (*[1 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt]j : 0// 保存接口的第i个方法对应的实际类型的方法的地址methods : (*[1 16]unsafe.Pointer)(unsafe.Pointer(m.fun[0]))[:ni:ni]var fun0 unsafe.Pointer imethods:// 遍历接口方法列表for k : 0; k ni; k {// 接口的方法i : inter.mhdr[k]// 接口的方法类型itype : inter.typ.typeOff(i.ityp)// 接口的方法名称name : inter.typ.nameOff(i.name)// 接口的方法名iname : name.name()// 接口的包路径ipkg : name.pkgPath()if ipkg {ipkg inter.pkgpath.name()}// 根据接口方法查找实际类型的方法for ; j nt; j {// 实际类型的方法t : xmhdr[j]// 实际类型的方法名tname : typ.nameOff(t.name)// 比较接口的方法名和实际类型的方法是否一致包括名称和类型if typ.typeOff(t.mtyp) itype tname.name() iname {pkgPath : tname.pkgPath()if pkgPath {pkgPath typ.nameOff(x.pkgpath).name()}// 如果是导出方法或在同一个包则将将方法保存到 itab 中if tname.isExported() || pkgPath ipkg {if m ! nil {// 实际类型的方法指针通过该指针可以调用实际类型的方法ifn : typ.textOff(t.ifn)if k 0 {fun0 ifn // well set m.fun[0] at the end} else {methods[k] ifn}}continue imethods}}}// 该类型没有实现接口// 如果每个接口方法都被实现了则每次都会走到 continue 的逻辑不会将 fuc[0] 置为 0m.fun[0] 0return iname}m.fun[0] uintptr(fun0)return } 主要逻辑是依次遍历接口的所有方法并在实际类型的接口列表中查找对应的实现只要有一个接口方法没有被实现则将itab的fun[0]置为0表示该类型没有实现该接口。 itabadd getitab方法如果没有找到itab会新建一个itab并调用itabAdd方法将其缓存到itabTable中。 func itabAdd(m *itab) {...t : itabTable// 容量超过 75% 时会触发扩容if t.count 3*(t.size/4) { // 75% load factor// 扩容为原哈希表的 2 倍大小t2 : (*itabTableType)(mallocgc((22*t.size)*goarch.PtrSize, nil, true))t2.size t.size * 2// 将原哈希表的元素复制到新哈希表// 复制过程中其他的线程可能会尝试从原哈希表中获取 itab但找不到。此时会尝试获取锁(会阻塞)后再次获取。iterate_itabs(t2.add)-】if t2.count ! t.count {throw(mismatched count during itab table copy)}// 使用原子操作将 itabTable 的引用指向新扩容的内存atomicstorep(unsafe.Pointer(itabTable), unsafe.Pointer(t2))// Adopt the new table as our own.t itabTable// Note: the old table can be GCed here.}// 将新的 itab 缓存到 itabTable 中t.add(m) } 3.3 接口赋值 将某一具体类型赋值给接口类型时本质其实时如何填充eface和iface结构体。 对eface结构体来说由于只有_type和data字段因此只需要进行字段赋值即可。 对于iface结构体来说需要通过itab判断类型值是否实现了接口的所有方法(itab可能不存在会走一遍getitab的流程)然后初始化iface结构的tab和data字段。 底层会调用runtime.convTXXX转换为iface或eface的data字段。 func convT(t *_type, v unsafe.Pointer) unsafe.Pointer {...// 分配_type所需的内存x : mallocgc(t.size, t, true)// 将v的值复制到刚分配的内存typedmemmove(t, x, v)return x }
http://www.zqtcl.cn/news/203022/

相关文章:

  • 免费网站源代码怎么制作网站教程
  • Thinkphp开发wordpress网站怎么优化seo
  • tp框架做视频网站站长统计芭乐鸭脖小猪
  • asp网站发布ftp国内f型网页布局的网站
  • 无限空间 网站四川省建设厅网站填报获奖
  • 广东佛山最新通知北京seo怎么优化
  • 浙江省通信管理局 网站备案 管理部门科技公司经营范围包括哪些
  • 网站域名备案转接入手续深圳外贸公司qc招聘
  • 湖北网站建设服务公司可以做产品推广的网站
  • 做经营性的网站备案条件wordpress删除菜单
  • js商城网站个安装wordpress
  • 想给学校社团做网站企业服务平台是做什么的
  • 网站推广渠道的类型wordpress看不到表格
  • 网站建设与推广实训报告册附近广告设计与制作门店电话
  • wordpress汉语公益网站开发使用api对seo
  • 北京网站优化前景seo网络推广专员
  • 临海网站制作工程施工合同免费版
  • 免费的黄冈网站有哪些平台wordpress 新闻发布
  • 给男票做网站表白的软件wordpress软件网站模板下载
  • 网站备案个人可以做吗dw制作一个手机网站模板
  • 如何识别一个网站是否做的好坏新河官网
  • 深圳网站建设 卓教育直播网站开发
  • 如何修改网站后台密码河南省罗山县做网站的公司
  • 个人网站免费源码大全湖南长沙新增病例最新消息
  • 途牛网站开发需求邯郸市中小学健康管理平台登录
  • 青岛商城网站开发年度关键词有哪些
  • 电商网站开发文献综述网站文案优化
  • 兼职工厂网站建设万维网的代表网站
  • 企业要建设一个网站需要多少钱网站制作的关键技术
  • 大连住房和城乡建设网站工程公司取名字大全