Golang - 结构体

Golang - 结构体

结构体说明

结构体(struct) 是用户自定义的类型,它代表若干字段(基本数据类型/引用数据类型)的集合。有些时候将多个数据看做一个整体要比单独使用这些数据更有意义,这种情况下就适合结构体。

比如将一个员工的name,department,salary三个属性打包在一起成为一个employee结构就很有意义的。

结构体类型

结构体是复合类型(composite types),当声明一个结构体变量的时候,内存空间就已经被分配,每个字段(field)为类型的0值。

Golang - 结构体

上面的内存示意图表明了,变量employee声明为Employee结构体类型的时候,会初始化该结构体中字段类型的0值,然后直接指向声明后的结构体,也可以说明:结构体类型。

不同的结构体类型变量字段是独立的,互不影响,一个结构体变量字段的更改,不影响另外一个结构体类型变量。

package main

import "fmt"

type Employee struct {
	Name,Department string
	Salary float32
	Task []string
}

func main()  {
	var employee1 = Employee{
		Name: "易文杰",
		Department: "系统开发部",
		Salary: 5000,
		Task: []string{
			"支付",
			"客户分配",
		},
	}

	employee2 := employee1
	employee2.Name = "张冲"

	fmt.Println(employee1,employee2)
}

上面的代码,声明了一个employee1变量后,将employee1赋值给employee2变量,当我们修改employee2的字段Name后,发现emloyee1中的Name并没有被更改。程序的输出结果:

{易文杰 系统开发部 5000 [支付 客户分配]} {张冲 系统开发部 5000 [支付 客户分配]}

结构体的声明

type Employee struct {
	Name string
	Department string
	Salary float32
}

上面的代码声明了一个名为Employee的结构体类型,它拥有Name,Department,Salary三个字段。同一个类型的多个字段可以合并到一行(用逗号进行分隔),并将类型放到后面。上面的结构体中NameDepartment都是string的类型,因此可以将它们写到一起。

type Employee struct {
	Name,Department string
	Salary float32
}

上面结构体Employee是一个具名结构体(named structure),因为它创建了一个具有名称的结构体类型:Employee。我们可以定义具名结构体类型的变量。

我们也可以定义一个没有类型名称的结构体,这种结构体叫做匿名结构体(anonymous structures)

var employee struct{
    Name,Department string
    Salary float32
}

当结构体中的字段是mapslice,指针的时候,默认的0值是nil(没有分配空间)的时候,需要分配空间后才能被使用

package main

import "fmt"

type Employee struct {
	Name,Department string
	Salary float32
	Mapper map[string]string
	Slicer []string
	Ptr *int
}

func main()  {
	var employee Employee

	employee.Name = "易文杰"
	employee.Department = "系统开发部"

	employee.Mapper = make(map[string]string)
	employee.Mapper["smile"] = "易文杰"

	employee.Slicer = make([]string,10)
	employee.Slicer[0] = "切片"

	age := 12
	employee.Ptr = &age

	fmt.Println(employee)
}

当未分配空间就直接使用,会导致代码异常

panic: assignment to entry in nil map

上面的程序会输出:

{易文杰 系统开发部 0 map[smile:易文杰] [切片         ] 0xc00000a098}

结构体的作用域

结构体采用首字母大小写来区分访问权限,当首字母是大写,可以别外包引用。反之,不能。

定义具名结构体变量

下面的程序说明了如何定义一个具名结构体Employee的变量

package main

import "fmt"

//定义结构体
type Employee struct {
	Name,Department string
	Salary float32
}

func main()  {
	//使用结构体一
	employee1 := Employee{
		Name: "易文杰",
		Department: "系统研发部",
		Salary: 5000,
	}

	//使用结构体二
	employee2 := Employee{"张冲","系统研发部",15000}

	fmt.Println(employee1,employee2)
}

在上面的程序中,我们定义了一个名叫Employee的结构体类型,我们可以通过指定字段的名称和对应的值来创建一个结构体变量。其中字段名和类型必须要和结构体中声明的保持一致。

采用第一种定义结构体变量:不需要和声明结构体中的变量顺序保持一致,但最后一个数据需保留,

采用第二种定义结构体变量:需要和声明结构体中的变量顺序保持一致,最后一个数据不需要保留,

上面的程序输出如下:

{易文杰 系统研发部 5000} {张冲 系统研发部 15000}

定义匿名结构体变量

package main

import "fmt"

func main()  {
	var employee = struct {
		Name,Department string
		Salary float32
	}{"张冲","系统开发部",28000}

	fmt.Println(employee)
}

在上面的程序中,我们定义了一个employee匿名结构体变量。这种结构体称为匿名结构体,因为它只创建了一个新的结构体变量employee,而没有定义新的结构体类型。

上面的程序输出为:

{张冲 系统开发部 28000}

访问结构体中的字段

使用.操作符来访问结构体中的字段

package main

import "fmt"

func main()  {
	var employee = struct {
		Name,Department string
		Salary float32
	}{"张冲","系统开发部",28000}

	fmt.Printf("姓名%v\n部门%v\n工资%v\n",employee.Name,employee.Department,employee.Salary)
}

在上面的程序中,通过employee.Name来访问employee中的字段Name。程序的输出为:

姓名张冲
部门系统开发部
工资28000

结构体指针

可以定义指向结构体的指针。

package main

import "fmt"

type Employee struct {
	Name,Department string
	Salary float32
}

func main()  {
	//方式一
	var employee1 = &Employee{
		Name: "张冲",
		Department: "系统研发部",
		Salary: 18000,
	}

	//方式二
	var employee2 = new(Employee)
	employee2.Name = "易文杰"

	fmt.Println(employee1.Name)
	fmt.Println((*employee1).Name)

	fmt.Println(employee2.Name)
	fmt.Println((*employee2).Name)
}

上面的程序中,employee1employee2是一个指向Employee结构体的指针。(*employee1).Name是访问employee1中的Name字段。程序的输出为:

张冲
张冲
易文杰
易文杰

在Go中我们可以使用employee.Name替代显示解引用(*employee).Name来访问Name字段。

上一篇:mybatis一对多,一对一使用场景


下一篇:sql优化-把派生表改成子查询,查询速度将变快