Go语言中的结构体类型

Go语言中的结构体类型,第1张

结构体 结构体的定义和初始化

除了int、float、字符串类型之外,实际开发过程中还会遇到很多更复杂的类型,比如一个学生、老师等等,就不能用基本类型来表示了。在C中用结构体来表示,在java中用类来定义,在Go中也用结构体来表示。比如我们定义一个学生结构体,代码如下:

// 定义一个结构体,和c的语法很相似
type student struct {
	name string
	age  int
	love []string
}

下面的代码中我们通过new关键字来分配一块内存,用来承载一个student结构体,stu可以看做一个指向这块内存的指针,stu := new(student)这行代码也可以写成var stu *student = new(student)这样,类似于C语言中常见的这种写法:student* stu = malloc(sizeof(struct student));。其含义就是定义 一个studnet类型的指针stu,并开辟一块内存空间,让stu指向这块空间。那么在java中,则是这样的写法Studnet stu = new Studnet()。意思是一样的。

func main() {
	stu := new(student)
	stu.age = 12
	stu.name = "hxy"
	stu.love = make([]string, 5)
	stu.love = append(stu.love, "sing", "pingpang")

	fmt.Println(*stu)
}

在上面的代码片段中,我们通过stu.age等这样的表达式给一个结构体实体的属性进行了赋值,如果属性多的话,这样写是有点麻烦的。有没有省事的办法呢。在C语言中我们可以通过下面的方式struct student stu = {.name = "hxy"}的方式初始化,java中可以通过构造函数的方式初始化,那么在Go语言中也有类似的语法,比如:

love := []string{"java", "go"}
// 按照结构体中属性定义的顺序初始化
stu := student{"hxy", 12, love}

// 为指定属性赋值,没有指定的为初始值
stu := student{name: "hxy", age: 12}

注意:

通过stu := new(student)这种方式创建一个结构体,我们说这里的stu是一个指针通过stu := student{"hxy", 12, love}这种方式呢,stu却不是一个指针,作为参数传递是值传递,具体参考下面几段代码
func main() {
	stu := student{name: "hxy", age: 12}
	modify(stu)
	fmt.Println(stu)
}

func modify(stu student) {
	stu.age = 20
}
// 输出  age并没有改变,传的不是地址
{hxy 12 []}
func main() {
	stu := student{name: "hxy", age: 12}
	modify(&stu) // 将stu的地址传过去,才是引用传递
	fmt.Println(stu)
}

// 这里应该接受一个student类型的指针
func modify(stu *student) {
	stu.age = 20
}

// 输出  age并没有改变,传的不是地址
{hxy 20 []}
func main() {
	stu := new(student)
	modify(stu)
	fmt.Println(*stu)
}

func modify(stu *student) {
	stu.age = 20
}

// 输出
{go 20 []}
带标签的结构体

在java编程中,经常我们会遇到对Bean做一些参数校验、json序列化的问题,这个时候我们经常会写一些注解去帮助我们做,比如@NotNull@Min(5)@JsonField等。或者也可以自定义一些注解,去做定制化的 *** 作。那么在Go语言中,也有类似的设计,叫做结构体的Tag。

Tag是在结构体编译阶段就关联到结构体中具体字段的一个原信息字符串,可以在运行的时候通过反射获取到,他可以由一个或者多个键值对的组成,键与值使用冒号分隔,值用双引号括起来。键值对之间使用一个空格分隔。比如:

type student struct {
    // 这里的tag是binding标签的一种用法,做参数校验
	name string `form:"name" binding:"required,min=1,max=10"`
	age  int    `form:"age" binding:"lte=150,gte=0"`
	sex  string `form:"sex" binding:"oneof=male female"`
}

func main() {
	stu := student{"hxy", 12, "male"}
	for i := 0; i < 3; i++ {
		stuType := reflect.TypeOf(stu)
		stuField := stuType.Field(i)
		fmt.Printf("%v\n", stuField.Tag)
	}
}

// 输出
form:"name" binding:"required,min=1,max=10"
form:"age" binding:"lte=150,gte=0"
form:"sex" binding:"oneof=male female"
匿名字段和内嵌结构体

我们都说封装、继承、多态是面向对象的三大特性,而C语言是面向过程的,但是C语言同样也可以实现所谓的封装、继承、多态。我们今天一起看看继承。

java中是通过extends关键字来实现对父类的继承,在C语言中我们可以通过组合来实现继承,比如下面这段代码。

struct Person {
    char[] name;
    int age;
}

struct Studnet {
    struct Person name;
    struct int id;
    struct float score;
}

而Go语言也借鉴了这种思想,即通过组合实现继承的特性。比如下面这段代码:

type person struct {
	name string
	age  int
	sex  string
}

type student struct {
	person
	score float32
}

func main() {
	stu := student{person{"hxy", 18, "man"}, 90.5}
	fmt.Println(stu)
	fmt.Println(stu.name)
}

// 输出
{{hxy 18 man} 90.5}
hxy

这里呢我们就通过在student中内嵌person来实现了继承的效果。可以看到在第8行只定义了字段的类型,没有显示的名字,这在Go语言里面是被允许的,叫做匿名字段。

结构体和方法

在java中,我们常常见到这样的写法,也就是用类来表示用户自定义的数据结构,里面声明属性,还可以声明一些方法。而在Go里面,用结构体来定义用户自定义的数据结构,也支持为结构体定义一些方法。

public class Student {
    private String name;
    private int age;
    public void printStu() {
        
    }
}

上面的java代码如果用Go来表示,就可以写成下面这样。我们在12行定义了一个方法,通过(stu *student)指定了这个方法的接受者为student。那么在18行就可以通过stu.printStu()的方法区进行调用了。

type person struct {
	name string
	age  int
	sex  string
}

type student struct {
	person
	score float32
}

func (stu *student) printStu() {
	fmt.Printf("%v\n", *stu)
}

func main() {
	stu := &student{person{"hxy", 18, "man"}, 90.5}
	stu.printStu()
}

注意:

为结构体定义方法,他们必须要求在同一个包里才行,否则会报错。如果不在一个包里,非要定义,那么可以通过定义别名的方式去间接的实现。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/990859.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存