Go中赋值和转换关系
创始人
2024-02-22 00:03:21
0

在这里插入图片描述

Go中的赋值跟类型转换:

在java中反射是可以获取继承关系,而go语言实际是不支持继承的,所以必须是相同的类型才能使用AssignableTo(),ConvertibleTo()

package mainimport ("fmt""reflect"
)type User struct {Name string
}
func demo(){user:=User{Name:"Hello",}u:=reflect.TypeOf(user)user2:=User{Name: "world",}u1:=reflect.TypeOf(user2)b:=u.AssignableTo(u1)//u1类型的是否可以赋值给u2类型的---实际就是判断一下 类型1跟类型2是否是同一类型fmt.Println(b)b1:=u.ConvertibleTo(u1)//是否可以转换fmt.Println(b1)
}func main() {demo()
}

在这里插入图片描述

Go中的伪继承

对比java中 的继承 (extends 关键字),Go中无extends关键字,这意味着Go中并没有对继承的支持。但是,Go使用interface实现的功能叫组合,Go是使用组合来实现的继承,说的更精确一点,是使用组合来代替的继承;

伪继承的实现:

話不多説,先看代码:

结构体的嵌套实现继承

package mainimport "fmt"//相当于java中的父类type Animal struct {name string
}//java中的 子类type Cat struct {//我要继承 AnimalAnimallike string
}//为猫定制的的方法func (c Cat) Eat() string {//可以看到我们没有在Cat中声明 name属性,但是这里可以使用Animal声明的namefmt.Println(c.name + "爱吃" + c.like)return c.like
}func (a Animal) Name() string {fmt.Println(a.name)return a.name
}func main() {a := Animal{name: "小动物",}c := Cat{Animal: Animal{name: "小猫猫",}, like: "小鱼干",}fmt.Println(c.Name() + c.Eat() + a.Name())
}

这样Cat就继承了Animal中的属性name;

输出结果:
在这里插入图片描述

简单来看这种继承的方式实际就是结构体的嵌套(刚开始学,不知道这样理解是否正确)

接下来我们使用接口的方式来进行封装:

接口的方式实现继承:

package mainimport "fmt"//一个接口type Animals interface {//接口中的方法eat()
}//一个结构体type Animal struct {name stringlike string
}
type Dog struct {AnimalsleepTime int
}type Cat struct {Animalhobby string
}// Dog也实现了 eat
func (d Dog) eat() {fmt.Println(d.like)
}// Cat也实现了 eat
func (c Cat) eat() {fmt.Println(c.like)
}//实现接口---即实现接口中的方法eatfunc (a Animal) eat() {fmt.Println(a.name + "爱吃" + a.like)
}func main() {c := Cat{Animal: Animal{name: "小花猫",like: "小鱼干",},hobby: "睡觉",}d := Dog{Animal: Animal{name: "大黄狗",like: "大棒骨",},sleepTime: 100,}testinter(c)testinter(d)
}
func testinter(animals Animals){animals.eat()
}

简单来讲跟结构体的嵌套差不多,只不过这次是实现接口,从代码的实际应用来讲,实现接口是为了实现特定的目的,这个跟java中接口的实现的作用是差不多的功能;

接口的实现判断:

增量代码:

fmt.Println("======================")//获取接口的类型//先传 nil 进来 强转为接口的指针,再来获得 其类型animals := reflect.TypeOf((*Animals)(nil)).Elem()//判断是否实现接口bools:=cat.Implements(animals)fmt.Println(bools)

在这里插入图片描述

implements 方法要求传入Type类型
不能直接传入接口,
这里通过 将nil强制转换为 接口指针,在然后判断其类型

于是reflect.TypeOf((*Animals)(nil)) 就会看起来很怪;

增量代码:

	c:=Cat{Animal: Animal{},hobby:  "小鱼干",}cc:=reflect.ValueOf(c)fmt.Println(cc.IsNil())//判断 cc 是否是 nil

// IsNil reports whether its argument v is nil. The argument must be
// a chan, func, interface, map, pointer, or slice value; if it is //
not, IsNil panics. Note that IsNil is not always equivalent to a //
regular comparison with nil in Go. For example, if v was created // by
calling ValueOf with an uninitialized interface variable i, // i==nil
will be true but v.IsNil will panic as v will be the zero // Value.

源码解释告诉我们 只有是chan, func, interface, map, pointer, or slice ,否则就会报错 ,所以在使用之前要判断一下是否符合调用的条件在做处理;

当同时调用 cc.IsNil() ,cc.isValid()时会出现错误,导致程序不能正常运行—>>

panic: reflect: call of reflect.Value.IsNil on struct Value
//不能对结构的值调用reflect.Value.IsNil
goroutine 1 [running]:
reflect.Value.IsNil(...)

注销掉其中一个—>>
在这里插入图片描述
运行结果如下:
在这里插入图片描述

值转为Type


func main() {//返回值为Value类型i:=reflect.ValueOf(100)g:=reflect.ValueOf("abc")//打印的是值fmt.Println(i)fmt.Println(g)//可以直接强转--如果确定数据类型的话fmt.Println(i.Int())fmt.Println(g.String())//将Value转为Typeh:=i.Type()k:=g.Type()//判断类型fmt.Println(h.Kind()==reflect.Int)fmt.Println(k.Kind()==reflect.String)
}

Golang中的reflect.Elem()函数用于获取接口v包含的值或指针v指向的值

调用该函数Elem()只能是接口指针

反射修改数据

通过反射可以修改原始变量的值,但是需要一定的条件支持,传入的实参必须是指针类型

package mainimport ("fmt""reflect"
)func main(){//字符串var s ="hello"//这里要传指针,否则不会修改vs:=reflect.ValueOf(&s)vs.Elem().SetString("world")fmt.Println(s)
}

这里通过 Elem()方法把指针Value转换为非指针Value----即通过反射获取指针指向的元素类型,这个获取过程被称为取元素,等效于对指针类型变量做了一个*操作

我们来操作一下struct

package mainimport ("fmt""reflect"
)type user struct {name stringage int
}
func main(){//字符串var s ="hello"//这里要传指针,否则不会修改vs:=reflect.ValueOf(&s)vs.Elem().SetString("world")fmt.Println(s)u:=user{name: "小红",age: 18,
}
h:=reflect.ValueOf(&u)//传指针
k:=h.Elem().FieldByName("name")//根据属性名获取值 Elem将其转为值
fmt.Println(k)
fmt.Println(k.CanSet())//只有值是可寻址的时候才可以被修改---即可以被外界访问的
if k.CanSet(){k.SetString("小明")//k.Elem().SetString("小明")fmt.Println(u.name)
}
}

输出结果:
在这里插入图片描述
因为这里name属性的访问权限问题,所以 canSet()的结果为false, 我们将user属性name改为"Name" 再来看输出结果—>>
在这里插入图片描述
当 我们通过反射去修改结构体中的属性时,这个属性 要是能够被访问的—即首字母大写,
如果是接口中的即使时小写的也可以被访问;

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...