Go 结构体的使用
结构体是用户定义的类型,表示若干个字段(Field)的集合。有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体。
例如,一个职员有 firstName、lastName 和 age 三个属性,而把这些属性组合在一个结构体 employee 中就很合理。
结构体的声明基础
type Employee struct {
firstName string
lastName string
age int
}
在上面的代码片段里,声明了一个结构体类型 Employee,它有 firstName、lastName 和 age 三个字段。通过把相同类型的字段声明在同一行,结构体可以变得更加紧凑。在上面的结构体中,firstName 和 lastName 属于相同的 string 类型,于是这个结构体可以重写为:
type Employee struct {
firstName, lastName string
age, salary int
}
上面的结构体 Employee 称为 命名的结构体(Named Structure)。我们创建了名为 Employee 的新类型,而它可以用于创建 Employee 类型的结构体变量。
声明结构体时也可以不用声明一个新类型,这样的结构体类型称为 匿名结构体(Anonymous Structure)。
var employee struct {
firstName, lastName string
age int
}
上述代码片段创建一个匿名结构体 employee 。
emp3 := struct {
firstName, lastName string
age, salary int
}{
firstName: "Andreah",
lastName: "Nikola",
age: 31,
salary: 5000,
}
上述代码片段通过匿名结构体 创建了一个结构体变量 。
结构体基础使用
- 结构体变量初始化
- 结构体指针变量初始化
- 结构体变量之间的比较与赋值
- 在函数中传递结构体变量与结构体指针变量
- 定义结构体函数成员与调用
package main import (
"fmt"
)
//结构体为类型定义
//创建一个结构体,四个数据属性,四个函数属性
/////////////////////////////////////
type Person struct {
name string
age int
sex bool
//hobby []string
} //*Person意味传递是真实地址
func (p *Person)Eat(){
fmt.Printf("%s爱吃西红柿炒鸡蛋\n",p.name)
}
func (p *Person)Drink(){
fmt.Printf("%s爱喝可乐\n",p.name)
}
func (p *Person)Sleep(){
fmt.Printf("%s要睡8个小时\n",p.name)
}
func (p *Person)Love(){
fmt.Printf("%s喜欢\n",p.name)
}
//////////////////////////////////////////// //值传递与属性传递
////////////////////////
func MakeHimLove(p Person){p.Love()} func MakeHisPtrLove(p *Person){p.Love()}
///////////////////// func main(){ //////结构体变量初始化///////////////
//顺序初始化:创建对象时按顺序给所有属性赋值
p1 := Person{"lili",8,true}
fmt.Println(p1)
//指定成员初始化:指定成员变量进行赋值,没有指定的成员变量为默认值
p2 := Person{name:"mingming",sex:true} //--未初始化的成员变量,取该数据类型的默认值。
fmt.Println(p2)
//创建后初始化:
p3 := Person{} //--未初始化的成员变量,取该数据类型的默认值。
p3.name ="xiaoli"
p3.age =19
fmt.Println(p3)
//////////////////////// ///////////结构体指针变量初始化///////////// //一般初始化
var p4 *Person = &Person{"weiai",26,true}
fmt.Println(p4) //使用new初始化
p5 := new(Person)
p5.name ="titi"
p5.age =31
p5.sex =false
//注意:在64位操作系统下,所有类型的指针,均为8个字节
//////////////////////// ///////////结构体变量的比较和赋值/////////////
//1.比较:只能使用 ==和!= 不能使用 > < >= <=
//注意:结构体有些类型存在,结构体变量是不能进行比较的,如:[]string
//结构体是值类型。如果它的每一个字段都是可比较的,则该结构体也是可比较的。如果两个结构体变量的对应字段相等,则这两个变量也是相等的。
fmt.Println("p1 == p2:",p1 == p2)
//2.赋值:相同类型结构体可以直接赋值
var temp Person
temp = p1
fmt.Println(temp)
//////////////////////// ////////////函数内部使用结构体传参/////////////
//值传递传递的是副本,引用传递传递的才是本身
//注意:值传递内存消耗大,效率低
//unasfe.Sizeof(变量名):查看变量所占的内存空间大小
//要求传递值就必须传递值
//MakeHimLove(p1)
//要求传递指针就必须传递指针:地址传递、引用传递
//结构体变量的地址为结构体首个元素的地址
//MakeHisPtrLove(&p1)
///////////////////// ////////////结构体调用自身函数//////////////////
/////////////////////
// //实例调用方法
// p1.Eat()
// p1.Drink()
// p1.Sleep()
// p1.Love()
///////////////////////////////////////////// }
补充知识点
- 匿名字段
- 嵌套结构体(Nested Structs)
- 提升字段(Promoted Fields)
导出结构体和字段
匿名字段
当我们创建结构体时,字段可以只有类型,而没有字段名。这样的字段称为匿名字段(Anonymous Field)。
以下代码中有 Person 结构体,它含有两个匿名字段 string 和 int。
package main import (
"fmt"
)
type Person struct {
string
int
} func main() {
p := Person{"Naveen", 50}
fmt.Println(p)
}
该程序输出 {Naveen 50}。
虽然匿名字段没有名称,但其实匿名字段的名称就默认为它的类型。比如在上面的 Person 结构体里,虽说字段是匿名的,但 Go 默认这些字段名是它们各自的类型。所以 Person 结构体有两个名为 string 和 int 的字段。
嵌套结构体(Nested Structs)
结构体的字段有可能也是一个结构体。这样的结构体称为嵌套结构体。
package main import (
"fmt"
) type Address struct {
city, state string
}
type Person struct {
name string
age int
address Address
} func main() {
var p Person
p.name = "Naveen"
p.age = 50
p.address = Address {
city: "Chicago",
state: "Illinois",
}
fmt.Println("Name:", p.name)
fmt.Println("Age:",p.age)
fmt.Println("City:",p.address.city)
fmt.Println("State:",p.address.state)
}
上面的结构体 Person 有一个字段 address,而 address 也是结构体。该程序输出:
Name: Naveen
Age: 50
City: Chicago
State: Illinois
提升字段(Promoted Fields)
如果是结构体中有匿名的结构体类型字段,则该匿名结构体里的字段就称为提升字段。这是因为提升字段就像是属于外部结构体一样,可以用外部结构体直接访问。我知道这种定义很复杂,所以我们直接研究下代码来理解吧。
type Address struct {
city, state string
}
type Person struct {
name string
age int
Address
}
在上面的代码片段中,Person 结构体有一个匿名字段 Address,而 Address 是一个结构体。现在结构体 Address 有 city 和 state 两个字段,访问这两个字段就像在 Person 里直接声明的一样,因此我们称之为提升字段。
package main import (
"fmt"
) type Address struct {
city, state string
}
type Person struct {
name string
age int
Address
} func main() {
var p Person
p.name = "Naveen"
p.age = 50
p.Address = Address{
city: "Chicago",
state: "Illinois",
}
fmt.Println("Name:", p.name)
fmt.Println("Age:", p.age)
fmt.Println("City:", p.city) //city is promoted field
fmt.Println("State:", p.state) //state is promoted field
}
在上面代码中的第 26 行和第 27 行,我们使用了语法 p.city 和 p.state,访问提升字段 city 和 state 就像它们是在结构体 p 中声明的一样。该程序会输出:
Name: Naveen
Age: 50
City: Chicago
State: Illinois
导出结构体和字段
如果结构体名称以大写字母开头,则它是其他包可以访问的导出类型(Exported Type)。同样,如果结构体里的字段首字母大写,它也能被其他包访问到。
让我们使用自定义包,编写一个程序来更好地去理解它。
在你的 Go 工作区的 src 目录中,创建一个名为 structs 的文件夹。另外在 structs 中再创建一个目录 computer。
在 computer 目录中,在名为 spec.go 的文件中保存下面的程序。
package computer
type Spec struct { //exported struct
Maker string //exported field
model string //unexported field
Price int //exported field
}
上面的代码片段中,创建了一个 computer 包,里面有一个导出结构体类型 Spec。Spec 有两个导出字段 Maker 和 Price,和一个未导出的字段 model。接下来我们会在 main 包中导入这个包,并使用 Spec 结构体。
package main import "structs/computer"
import "fmt" func main() {
var spec computer.Spec
spec.Maker = "apple"
spec.Price = 50000
fmt.Println("Spec:", spec)
}
包结构如下所示:
src
structs
computer
spec.go
main.go
在上述程序的第 3 行,我们导入了 computer 包。在第 8 行和第 9 行,我们访问了结构体 Spec 的两个导出字段 Maker 和 Price。执行命令 go install structs 和 workspacepath/bin/structs,运行该程序。
如果我们试图访问未导出的字段 model,编译器会报错。将 main.go 的内容替换为下面的代码。
package main import "structs/computer"
import "fmt" func main() {
var spec computer.Spec
spec.Maker = "apple"
spec.Price = 50000
spec.model = "Mac Mini"
fmt.Println("Spec:", spec)
}
在上面程序的第 10 行,我们试图访问未导出的字段 model。如果运行这个程序,编译器会产生错误:spec.model undefined (cannot refer to unexported field or method model)。
refer:『GCTT 出品』Go 系列教程 —— 第 16 部分:结构体
Go 结构体的使用的更多相关文章
- Go结构体实现类似成员函数机制
Go语言结构体成员能否是函数,从而实现类似类的成员函数的机制呢?答案是肯定的. package main import "fmt" type stru struct { testf ...
- C#基础回顾(二)—页面值传递、重载与重写、类与结构体、装箱与拆箱
一.前言 -孤独的路上有梦想作伴,乘风破浪- 二.页面值传递 (1)C#各页面之间可以进行数据的交换和传递,页面之间可根据获取的数据,进行各自的操作(跳转.计算等操作).为了实现多种方式的数据传递,C ...
- go语言结构体
定义: 是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体. 成员: 每个值称为结构体的成员. 示例: 用结构体的经典案例处理公司的员工信息,每个员工信息包含一个唯一的员工编号.员工的名字. ...
- C语言中的结构体
用户自己建立自己的结构体类型 1. 定义和使用结构体变量 (1).结构体的定义 C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体. (2).声明一个结构体类型的一般形式为: ...
- C++_系列自学课程_第_12_课_结构体
#include <iostream> #include <string> using namespace std; struct CDAccount { double bal ...
- java socket传送一个结构体给用C++编写的服务器解析的问题
另一端是Java写客户端程序,两者之间需要通信.c++/c接收和发送的都是结构体,而Java是直接发送的字节流或者byte 数组.解决方法:c++/c socket 在发送结构体的时候其实发送的也是字 ...
- swift学习笔记3——类、结构体、枚举
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- HDOJ 1009. Fat Mouse' Trade 贪心 结构体排序
FatMouse' Trade Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- C语言结构体对齐
1.结构体变量中的元素如何访问? (1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式):实质上都是指针方式访问.(2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来 ...
- C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用
类型 普通指针 指针数组(非指针类型) 数组指针 结构体指针 函数指针 二重指针 定义方式 int *p; int *p[5]; int (*p)[5]; int a[3][5]; struct{.. ...
随机推荐
- yml内容如何转map?
yml内容如何转map 解决方法: Map map = null; Yaml yaml = new Yaml(); File ymlFile = new File("c:/src/tes ...
- 123457123457#0#-----com.yuming.TruckCarRun01--前拼后广--大卡车游戏cym
com.yuming.TruckCarRun01--前拼后广--大卡车游戏cym
- tensorflow学习 从入门到实战(转)
原文作者:zhaozhengcoder链接:https://www.jianshu.com/p/27a2fb320934來源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处. ...
- mysql新建数据库(database)设置为utf8
CREATE DATABASE IF NOT EXISTS yourdbname DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
- iOS-常见问题(错误和警告)
1.storyboard连线问题 产生原因:将与storyboard关联的属性删除了,但是storyboard中还保持之前所关联的属性. 解决:取消关联就没事了. 2.XXXXX ...
- iOS算法题
1兔子算法题 兔子可以跳一步2步或者3步,问跳到100有多少种跳法? // 兔子可以跳一步2步或者3步 // 问跳到100有几种跳法 /* 分析1 两个变量,X*2+Y*3=100. X最大为50,X ...
- Docker storage driver(十四)
目录 一.storage driver 作用 1.Images and layers 2.Container and layers Copy-on-Write 3.Data volumes and t ...
- 前端nginx配置
对nginx还是处于小白阶段,知道的只是简单基础,以下配置没有问题,已实现 文件:nginx-1.15.11\conf\nginx.conf 注释:# 后台接口 :location ^~ /geste ...
- 用Inno setup制作以管理员权限启动的安装包
inno setup制作的安装包,默认是不需要管理员权限启动的.我们制作安装包,往往需要做一些设置工作,这些设置工作可能用到管理员权限.使用Resource Hacker修改inno setup资源, ...
- 日常工作问题解决:配置NTP服务器以及一些常见错误解决
1.配置NTP服务端 环境:redhat 6.5 服务器主机名 ip地址 说明 server 192.168.57.20 NTP服务端 client 192.168.57.21 NTP客户端 搭建说明 ...