包罗万象的结构体 -- 就要学习 Go 语言

栏目: Go · 发布时间: 6年前

内容简介:Go 语言的数组可以存储一组相同类型的数据,而结构体可以将不同类型的变量数据组合在一起,每一个变量都是结构体的成员。可以使用下面的语法创建一个结构体:创建一个含有

Go 语言的数组可以存储一组相同类型的数据,而结构体可以将不同类型的变量数据组合在一起,每一个变量都是结构体的成员。

创建并初始化一个结构体

可以使用下面的语法创建一个结构体:

type StructName struct{
    field1 fieldType1
    field2 fieldType2
}
复制代码

创建一个含有 firstNamelastNamesalaryfullTime 成员变量的结构体 Employee

type Empolyee struct{
	firstName string
	lastName string
	salary int
	fullTime bool
}
复制代码

相同类型的成员变量可以放在一行,所以,上面的代码可以简写成:

type Empolyee struct{
	firstName,lastName string
	salary int
	fullTime bool
}
复制代码

使用类型别名 Employee 创建一个结构体变量 ross

var ross Empolyee
ross.firstName = "ross"
ross.lastName = "Bingo"
ross.salary = 1000
ross.fullTime = true
fmt.Println(ross)
复制代码

输出:

{ross Bingo 1000 true}
复制代码

上面的代码创建了结构体变量 ross ,并为每一个成员变量赋值。使用 . 访问结构体的成员。

还可以使用 字面量 的方式初始化结构体:

1、方式一
ross := Empolyee{
	"ross",
	"Bingo",
	1000,
	true,
}
输出:{ross Bingo 1000 true}

2、方式二
ross := Empolyee{
	lastName:"Bingo",
	firstName:"ross",
	salary:1000,
}
输出:{ross Bingo 1000 false}
复制代码

方式一,初始化时省略了成员变量名称,但是必须按顺序地将给出所有的成员的值。必须记住所有成员的类型且按顺序赋值,这给开发人员带来了额外的负担且代码的维护性差,一般不采用这种方式;

提倡采用方式二,不用关心成员变量的顺序,给需要初始化的成员赋值,未赋值的成员默认就是类型对应的零值。 注意 :方式一和方式二初始化方式不可以混用

ross := Empolyee{
	firstName:"ross",
	lastName:"Bingo",
	1000,
	fullTime:true,
}
复制代码

编译出错: mixture of field:value and value initializers

成员变量的顺序对于结构体的同一性很重要,如果将上面的 firstNamelastName 互换顺序或者将 fullTimesalary 互换顺序,都是在定义一个不同的结构体类型

结构体指针

初始化结构体的时候,可以声明一个指向结构体的指针:

ross_pointer := &Empolyee{
	firstName:"ross",
	lastName:"Bingo",
	salary:1000,
	fullTime:true,
}
复制代码

上面的代码,创建了一个指向 Empolyee 结构体的指针 ross_pointer 。可以通过指针访问结构体的成员:

fmt.Println(*ross_pointer)
fmt.Println("firstName:",(*ross_pointer).firstName)
fmt.Println("firstName:",ross_pointer.lastName)
复制代码

输出:

{ross Bingo 1000 true}
firstName: ross
firstName: Bingo
复制代码

ross_pointer 是一个结构体变量,所以 (*ross_pointer).firstNameross_pointer.lastName 都是正确的访问方式 。

匿名成员

定义结构体时可以只指定成员类型,不用指定成员名,Go 会自动地将成员类型作为成员名。这种结构体成员称为 匿名成员 。这个结构体成员的类型必须是命名类型或者是指向命名类型的指针。

type Week struct{
	string
	int
	bool
}
func main() {
	week := Week{"Friday",1000,true}
	fmt.Println(week)
}
复制代码

上面的代码定义了结构体 Week ,有 stringintbool 三个成员变量,变量名与类型相同。 这种定义方式可以和指定成员名混合使用,例如:

type Empolyee struct{
	firstName,lastName string
	salary int
	bool
}
复制代码

结构体嵌套

Go 有 结构体嵌套 机制,一个结构体可以作为另一个结构体类型的成员。

type Salary struct {
	basic int
	workovertime int
}

type Empolyee struct{
	firstName,lastName string
	salary Salary
	bool
}

func main() {
	ross := Empolyee{
	    firstName:"Ross",
            lastName:"Bingo",
            bool:true,
            salary:Salary{1000,100},
	}
	fmt.Println(ross.salary.basic);
}
复制代码

我们新定义了结构体类型 Salary ,将 Empolyee 成员类型修改成结构体类型 Salary 。 创建了结构体 ross ,想要访问成员 salary 里面的成员还是可以采用 . 的方式,例如: ross.salary.basic

如果结构体嵌套层数过多时,想要访问最里面结构体成员时,采用上面这种访问方式就会牵扯很多中间变量,造成代码很臃肿。可以采用上面的匿名成员方式简化这种操作。

采用匿名成员方式重新定义结构体类型 Empolyee

type Empolyee struct{
	firstName,lastName string
	Salary    // 匿名成员
	bool
}
func main() {
	ross := Empolyee{
		firstName:"Ross",
		lastName:"Bingo",
		bool:true,
		Salary:Salary{1000,100},
	}
	fmt.Println(ross.basic);         // 访问方式一
	fmt.Println(ross.Salary.basic);  // 访问方式二
	ross.basic = 1200
	fmt.Println(ross.basic)          // update
}
复制代码

上面两种方式是等价的。通过这种方式,简化了访问过程。

需要 注意 的是,被嵌套的匿名结构体成员中,不能与上一层结构体成员同名。

type Empolyee struct{
	firstName,lastName string
	Salary
	basic int
	bool
}
func main() {
	ross := Empolyee{
		firstName:"Ross",
		lastName:"Bingo",
		bool:true,
		Salary{1000,100},
	}
	fmt.Println(ross.basic)
}
复制代码

上面的代码,我们修改了结构体 Empolyee ,多添加了一个与 Salary.basic 同名的成员,但是编译出错: mixture of field:value and value initializers

可导出的成员

一个 Go 包中的变量、函数首字母大写,那这个变量或函数是可以导出的。这是 Go 最主要的访问控制机制。如果一个结构体的成员变量名首字母大写,那这个成员也是可导出的。一个结构体可以同时包含可导出和不可导出的成员变量。

在路径 WORKSPACE/src/org/employee.go 创建一个名为 org 的包,添加如下代码:

// employee.go
package org
type Employee struct {
	FirstName,LastName string
	salary int
	fullTime bool
}
复制代码

上面的 Employee 结构体,只有变量 FirstNameLastName 是可导出的。当然, Employee 也是可导出的。 在 main 包中导入 org 包:

// main.go
package main
import (
	"org"
	"fmt"
)
func main() {
	ross := org.Employee{
		FirstName:"Ross",
		LastName:"Bingo",
		salary:1000,     
	}
	fmt.Println(ross)
}
复制代码

上面的代码编译出错,因为成员变量 salary 是不可导出的: unknown field 'salary' in struct literal of type org.Employee

因为 Employee 来自包 org ,所以用 org.Employee 去创建结构体 ross 。可以采用类型别名简化:

package main

import (
	"org"
	"fmt"
)

type Employee org.Employee; 

func main() {
	ross := Employee{
		FirstName:"Ross",
		LastName:"Bingo",
	}
	fmt.Println(ross)
}
复制代码

输出:

{Ross Bingo 0 false}
复制代码

结构体比较

如果结构体的所有成员都是可比较的,则这个结构体就是可比较的。可以使用 ==!= 作比较,其中 == 是按照顺序比较两个结构体变量的成员变量。

type Employee struct {
	FirstName,LastName string
	salary int
	fullTime bool
}
func main() {
	ross := Employee{
		FirstName:"Ross",
		LastName:"Bingo",
	}
	jack := Employee{
		FirstName:"Jack",
		LastName:"Lee",
	}
	fmt.Println(ross == jack)
}
复制代码

输出:

false
复制代码

不同类型的结构体变量是不能比较的:

type User struct {
	username string
}
type Employee struct {
	FirstName,LastName string
	salary int
	fullTime bool
}
func main() {
	ross := Employee{
		FirstName:"Ross",
		LastName:"Bingo",
	}
	user := User{
		username:"Seekload",
	}
	fmt.Println(ross == user)
}
复制代码

编译出错: invalid operation: ross == user (mismatched types Employee and User) .

然而,如果有成员是不能比较的,例如: map ,则这个结构体是不能比较的。

关注公众号「Golang来了」,获取最新文章!

包罗万象的结构体 -- 就要学习 Go 语言

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Speed Up Your Site

Speed Up Your Site

Andrew B. King / New Riders Press / 2003-01-14 / USD 39.99

There's a time bomb on the web: user patience. It starts ticking each time someone opens one of your pages. You only have a few seconds to get compelling content onto the screen. Fail, and you can kis......一起来看看 《Speed Up Your Site》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具