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

Go——面向对象

一. 匿名字段

        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 "fmt"type 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 ("bytes""io""os"
)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:指向实际的类型。上面案例是IInterfaceImpl
  • data:指向实际的值。上面案例是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(ni+nt) 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 + _type,value就是对应的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判断是否panic,canfail为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 // we'll 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((2+2*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 GC'ed 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
}

相关文章:

Go——面向对象

一. 匿名字段 go支持只提供类型而不写字段名的方式&#xff0c;也就是匿名字段&#xff0c;也称为嵌入字段。 同名字段的情况 所以自定义类型和内置类型都可以作为匿名字段使用 指针类型匿名字段 二.接口 接口定义了一个对象的行为规范&#xff0c;但是定义规范不实现&#xff…...

身份证识别ocr、身份证实名认证接口文档

每一次验证背后&#xff0c;都是对用户数据安全的承诺&#xff0c;对平台信誉的坚守。翔云身份证实名认证API&#xff0c;通过身份证识别接口仅需一键上传身份证图片即可快速识别身份证信息&#xff0c;翔云实名认证接口实时联网查验证件信息的真伪。 ​PHP身份证实名认证接口…...

C++ 文件操作

C中对文件操作需要包含头文件 < fstream > 文件类型分为两种&#xff1a; 1 . 文本文件 - 文件以文本的**ASCII码**形式存储在计算机中 2 . 二进制文件 - 文件以文本的**二进制**形式存储在计算机中&#xff0c;用户一般不能直接读懂它们 操作文件的三大类: 1 . ofstream…...

【数据结构】-- 单链表 vs 双向链表

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;python从入门到精通&#xff0c;魔法指针&#xff0c;进阶C&#xff0c;C语言&#xff0c;C语言题集&#xff0c;C语言实现游戏&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文…...

暴雨孙辉:做好服务器,但更要辟出技术落地之道

稳扎稳打一直是暴雨的风格&#xff0c;这在被访者孙辉的身上尽显。作为暴雨&#xff08;武汉暴雨信息发展有限公司&#xff09;中国区销售及市场副总裁&#xff0c;在谈及公司的技术发展与市场推广走势之时&#xff0c;孙辉沉稳、敏锐且逻辑清晰。 因在服务器领域起步很早&…...

天地人和•大道不孤——卢禹舜中国画作品展在重庆美术馆隆重开幕

2024年4月12日&#xff0c;由中国国家画院、重庆市文化和旅游发展委员会主办&#xff0c;重庆美术馆&#xff08;重庆画院、重庆国画院&#xff09;、北京八荒锦绣美术馆、中国国际文化交流基金会卢禹舜艺术基金承办的“天地人和•大道不孤——卢禹舜中国画作品展”开幕式在重庆…...

python-pytorch使用日志0.5.007

python-pytorch使用日志 1. optimizer.zero_grad()和model.zero_grad()的区别2. cbow和skip-gram的训练数据格式3. 获取cbow和skip-gram训练后的中文词向量4. 获取到词向量后可以做什么5. 余弦相似度结果的解释 1. optimizer.zero_grad()和model.zero_grad()的区别 都是清空模…...

itop4412编译内核时garbage following instruction -- `dmb ish‘ 解决方案

王德法 没人指导的学习路上磕磕绊绊太耗费时间了 今天编译4412开发板源码时报 garbage following instruction – dmb ish’ 以下是解决方案&#xff1a; 1.更新编译器 sudo apt-get install gcc-arm-linux-gnueabi 更新后修改Makefile 中编译器路径如下图 2.你以为更新完就可…...

(学习日记)2024.04.16:UCOSIII第四十四节:内存管理

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…...

微信小程序Skyline模式下瀑布长列表优化成虚拟列表,解决内存问题

微信小程序长列表&#xff0c;渲染的越多就会导致内存吃的越多。特别是长列表的图片组件和广告组件。 为了解决内存问题&#xff0c;所以看了很多人的资料&#xff0c;都不太符合通用的解决方式&#xff0c;很多需要固定子组件高度&#xff0c;但是瀑布流是无法固定的&#xf…...

大语言模型LLM《提示词工程指南》学习笔记03

文章目录 大语言模型LLM《提示词工程指南》学习笔记03链式提示思维树检索增强生成自动推理并使用工具自动提示工程师Active-Prompt方向性刺激提示Program-Aided Language ModelsReAct框架Reflexion多模态思维链提示方法基于图的提示大语言模型LLM《提示词工程指南》学习笔记03 …...

239. 奇偶游戏(带权值并查集,邻域并查集,《算法竞赛进阶指南》)

239. 奇偶游戏 - AcWing题库 小 A 和小 B 在玩一个游戏。 首先&#xff0c;小 A 写了一个由 0 和 1 组成的序列 S&#xff0c;长度为 N。 然后&#xff0c;小 B 向小 A 提出了 M 个问题。 在每个问题中&#xff0c;小 B 指定两个数 l 和 r&#xff0c;小 A 回答 S[l∼r] 中…...

程序员做副业,AI头条,新赛道

大家好&#xff0c;我是老秦&#xff0c;6年编程&#xff0c;自由职业3年&#xff0c;今天继续更新副业内容。 在当今信息爆炸的时代&#xff0c;副业赚钱已成为许多人增加收入的重要途径。其中&#xff0c;AI头条模式以其独特的优势&#xff0c;吸引了越来越多的写作者加入。…...

Redis: 内存回收

文章目录 一、过期键删除策略1、惰性删除2、定时删除3、定期删除4、Redis的过期键删除策略 二、内存淘汰策略1、设置过期键的内存淘汰策略2、全库键的内存淘汰策略 一、过期键删除策略 1、惰性删除 顾名思义并不是在TTL到期后就立即删除&#xff0c;而是在访问一个key的时候&…...

【刷题篇】回溯算法(三)

文章目录 1、全排列2、子集3、找出所有子集的异或总和再求和4、全排列 II5、电话号码的字母组合6、括号生成 1、全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 class Solution { public:vector<vector<i…...

pe格式从入门到图形化显示(八)-导入表

文章目录 前言一、什么是Windows PE格式中的导入表&#xff1f;二、解析导入表并显示1.导入表的结构2.解析导入表3.显示导入表 前言 通过分析和解析Windows PE格式&#xff0c;并使用qt进行图形化显示 一、什么是Windows PE格式中的导入表&#xff1f; 在Windows中&#xff0…...

如何将Paddle(Lite)模型转换为TensorFlow(Lite)模型

模型间的相互转换在深度学习应用中很常见&#xff0c;paddlelite和TensorFlowLite是移动端常用的推理框架&#xff0c;有时候需要将模型在两者之间做转换&#xff0c;本文将对转换方法做说明。 环境准备 建议使用TensorFlow2.14&#xff0c;PaddlePaddle 2.6 docker pull te…...

最新Zibll子比主题V7.1版本源码 全新推出开心版

源码下载地址&#xff1a;Zibll子比主题V7.1.zip...

响应式布局(其次)

响应式布局 一.响应式开发二.bootstrap前端开发框架1.原理2.优点3.版本问题4.使用&#xff08;1&#xff09;创建文件夹结构&#xff08;2&#xff09;创建html骨架结构&#xff08;3&#xff09;引入相关样式&#xff08;4&#xff09;书写内容 5.布局容器&#xff08;已经划分…...

arhtas idea plugin 使用手册

arthas idea plugin 使用文档 语雀...

数组算法——查询位置

需求 思路 使用二分查找找到第一个值&#xff0c;以第一个值作为界限&#xff0c;分为左右两个区间在左右两个区间分别使用二分查找找左边的7,&#xff1a;找到中间位置的7之后&#xff0c;将中间位置的7作为结束位置&#xff0c;依次循环查找&#xff0c;知道start>end,返回…...

【解决leecode打不开的问题】使用chrome浏览器和其他浏览器均打不开leecode

问题描述&#xff1a; 能进入leetcode力扣官网但是对某些栏目加载不出来&#xff0c;比如学习栏目能完成加载、题库栏目不能加载。 解决方法一&#xff1a;cookies缓存问题 首先尝试删除浏览器cookie缓存。 因为以下原因&#xff1a; Cookies损坏或过期&#xff1a;有些网站…...

尝试在手机上运行google 最新开源的gpt模型 gemma

Gemma介绍 Gemma简介 Gemma是谷歌于2024年2月21日发布的一系列轻量级、最先进的开放语言模型&#xff0c;使用了与创建Gemini模型相同的研究和技术。由Google DeepMind和Google其他团队共同开发。 Gemma提供两种尺寸的模型权重&#xff1a;2B和7B。每种尺寸都带有经过预训练&a…...

56、巴利亚多利德大学、马德里卡洛斯三世研究所:EEG-Inception-多时间尺度与空间卷积巧妙交叉堆叠,终达SOTA!

本次讲解一下于2020年发表在IEEE TRANSACTIONS ON NEURAL SYSTEMS AND REHABILITATION ENGINEERING上的专门处理EEG信号的EEG-Inception模型&#xff0c;该模型与EEGNet、EEG-ITNet、EEGNex、EEGFBCNet等模型均是专门处理EEG的SOTA。 我看到有很多同学刚入门&#xff0c;不太会…...

ORA-00600: internal error code, arguments: [krbcbp_9]

解决方案 1、清理过期 2、control_file_record_keep_time 修改 恢复时间窗口 RMAN (Recovery Manager) 是 Oracle 数据库的备份和恢复工具。在 RMAN 中&#xff0c;可以使用“恢复窗口”的概念来指定数据库可以恢复到的时间点。这个时间点是基于最近的完整备份或增量备份。 …...

uni-app实现分页--(2)分页加载,首页下拉触底加载更多

业务逻辑如下&#xff1a; api函数升级 定义分页参数类型 组件调用api传参...

前端工程化理解 (2024 面试题)

最好介绍远古世界最好随性一点&#xff0c;不要太刻板 &#xff0c;不然像背书 什么是前端工程化&#xff1f; - 知乎 前端工程化的历史 互联网初期&#xff0c;09 年以前&#xff0c;页面只需要展示一些列表、表格、文章内容以及简单图片即可&#xff0c;其目的是为了传送信…...

10 Php学习:循环

在 PHP 中&#xff0c;提供了下列循环语句&#xff1a; while - 只要指定的条件成立&#xff0c;则循环执行代码块do…while - 首先执行一次代码块&#xff0c;然后在指定的条件成立时重复这个循环for - 循环执行代码块指定的次数foreach - 根据数组中每个元素来循环代码块 当…...

FreeSWITCH 1.10.10 简单图形化界面17 - ubuntu22.04或者debian12 安装FreeSWITCH

FreeSWITCH 1.10.10 简单图形化界面17 - ubuntu22.04或者debian12 安装FreeSWITCH 界面预览00、先看使用手册0、安装操作系统1、下载脚本2、开始安装3、登录网页FreeSWITCH界面安装参考:https://blog.csdn.net/jia198810/article/details/132479324 界面预览 http://myfs.f3…...

ZStack Cloud 5.0.0正式发布——Vhost主存储、隔离PVLAN网络、云平台报警优化、灰度升级增强四大亮点简析

近日&#xff0c;ZStack Cloud 5.0.0正式发布&#xff0c;推出了包含Vhost主存储、隔离PVLAN网络、云平台报警优化、灰度升级增强在内的一系列重要功能。云主机管理、物理机运维、密评合规、灾备服务等诸多使用场景和功能模块均有更新&#xff0c;为您带来更完善的平台服务、更…...

五莲网站建设报价/请输入搜索关键词

一、编程语言分类&#xff1a;1、按特性分类&#xff1a;机器语言&#xff1a;编程入门非常困难&#xff0c;执行速度最快。汇编语言&#xff1a;编程相对机器语言简单&#xff08;采用助记符编程&#xff09;&#xff0c;针对某种具体的CPU。高级语言&#xff1a;贴近生活中的…...

网站排名做不上去吗/百度云盘下载

一、防sql注入办法 在apache commons-lang(2.3以上版本)中为我们提供了一个方便做转义的工具类&#xff0c;主要是为了防止sql注入&#xff0c;xss注入攻击的功能。总共提供了以下几个方法&#xff1a; 1.escapeSql 提供sql转移功能&#xff0c;防止sql注入攻击&#xff0c;例如…...

要维护公司的网站该怎么做/免费注册网址

2019独角兽企业重金招聘Python工程师标准>>> 今天决定看看开源中国安卓版app&#xff0c;并试着重构一下。好的进入主题。 创建MainActivity public class MainActivity extends ActionBarActivity implementsNavigationDrawerFragment.NavigationDrawerCallbacks,O…...

承德网站制作/微信营销的成功案例

题意 给定两个三角形的三点坐标和其速度矢量&#xff0c;询问两三角形是否会相撞&#xff0c;注意题目中描述&#xff0c;如果点相接触也算碰撞。 题解 首先求出相对速度&#xff0c;即让两速度矢量相减即可。这样就可以看做一个三角形静止&#xff0c;另一个运动了。此时&a…...

一人开公司做网站创业/构建新发展格局

为什么有条件变量&#xff1f; 请参看一个线程等待某种事件发生 注意&#xff1a;本文是linux c版本的条件变量和互斥锁(mutex)&#xff0c;不是C的。 mutex &#xff1a; mutual exclusion(相互排斥) 1&#xff0c;互斥锁的初始化&#xff0c;有以下2种方式。 调用方法的初始化…...

怎样查网站空间地址/歌尔股份砍单

1&#xff0c;无序情况 利用两个线性表L1&#xff0c;L2分别表示两个集合A,B&#xff0c;现在要求用一个新的集合A来表示归并后的集合&#xff0c;也就是在A的基础上把B中与A不同的元素归并到A中&#xff0c;这样得到的A就是两个集合的归并。 思路&#xff1a; 1>B中的元…...