Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >golang之Struct什么是结构体struct?

golang之Struct什么是结构体struct?

作者头像
若与
发布于 2018-04-25 06:40:01
发布于 2018-04-25 06:40:01
1.7K00
代码可运行
举报
运行总次数:0
代码可运行

最近在复习golang,学习的东西,如果不使用,很快就会忘记。所以,准备复习完golang,做一个练手的小项目,加深对golang的学习。今天开始公司,进入封闭式开发,所以每天晚上回来,学习golang时间比较少了。所以,争取一天一章的学习。

学习资源: https://github.com/Unknwon, 无闻,golang的大牛,他的文档网站很不错。教学也很好。golang的在线测试 https://play.golang.org,直接在浏览器中测试。

struct的主要内容:

结构体的定义和使用 使用字面量初始化 匿名结构和字段 结构体之间的比较和赋值 嵌入结构 提升字段 字段属性的访问使用 引用传递和值传递

什么是结构体struct?

结构体是用户定义的类型,表示若干个字段(Field)的集合。有时应该把数据整合在一起,而不是让这些数据没有联系。这种情况下可以使用结构体。就是面向对象编程语言中的类class

例如,一个职员有 firstNamelastNameage 三个属性,而把这些属性组合在一个结构体 employee 中就很合理。

结构体的声明

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Employee struct {
    firstName string
    lastName  string
    age       int
}

在上面的代码片段里,声明了一个结构体类型 Employee,它有 firstNamelastNameage 三个字段。通过把相同类型的字段声明在同一行,结构体可以变得更加紧凑。在上面的结构体中,firstNamelastName 属于相同的 string 类型,于是这个结构体可以重写为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Employee struct {
    firstName, lastName string
    age, salary         int
}

上面的结构体 Employee 称为 命名的结构体(Named Structure)。我们创建了名为 Employee 的新类型,而它可以用于创建 Employee 类型的结构体变量。

声明结构体时也可以不用声明一个新类型,这样的结构体类型称为 匿名结构体(Anonymous Structure)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var employee struct {
    firstName, lastName string
    age int
}

上述代码片段创建一个匿名结构体 employee。匿名结构体是使用字面量直接初始化的。

创建命名的结构体

通过下面代码,我们定义了一个命名的结构体 Employee

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {

    //creating structure using field names
    emp1 := Employee{
        firstName: "youdi",
        age:       25,
        salary:    500,
        lastName:  "liang",
    }

    //creating structure without using field names
    emp2 := Employee{"hui", "liang", 26, 800}

    fmt.Println("Employee 1", emp1)
    fmt.Println("Employee 2", emp2)
}

在上述程序的第 7 行,我们创建了一个命名的结构体 Employee。而在第 15 行,通过指定每个字段名的值,我们定义了结构体变量 emp1。字段名的顺序不一定要与声明结构体类型时的顺序相同。在这里,我们改变了 lastName 的位置,将其移到了末尾。这样做也不会有任何的问题。

在上面程序中,定义 emp2 时我们省略了字段名。在这种情况下,就需要保证字段名的顺序与声明结构体时的顺序相同。

该程序将输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 1 {youdi liang 25 500}
Employee 2 {hui liang 26 800}

创建匿名结构体

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
)

func main() {
    emp3 := struct {
        firstName, lastName string
        age, salary         int
    }{
        firstName: "Andreah",
        lastName:  "Nikola",
        age:       31,
        salary:    5000,
    }

    fmt.Println("Employee 3", emp3)
}

在上述程序的第 3 行,我们定义了一个匿名结构体变量 emp3。上面我们已经提到,之所以称这种结构体是匿名的,是因为它只是创建一个新的结构体变量 em3,而没有定义任何结构体类型。

该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 3 {Andreah Nikola 31 5000}

结构体的零值(Zero Value)

当定义好的结构体并没有被显式地初始化时,该结构体的字段将默认赋为零值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    var emp4 Employee //zero valued structure
    fmt.Println("Employee 4", emp4)
}

该程序定义了 emp4,却没有初始化任何值。因此 firstNamelastName 赋值为 string 的零值("")。零值是对应类型的零值。 而 agesalary 赋值为 int 的零值(0)。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 4 { 0 0}

当然还可以为某些字段指定初始值,而忽略其他字段。这样,忽略的字段名会赋值为零值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp5 := Employee{
        firstName: "John",
        lastName:  "Paul",
    }
    fmt.Println("Employee 5", emp5)
}

在上面程序中的第 14 行和第 15 行,我们初始化了 firstNamelastName,而 agesalary 没有进行初始化。因此 agesalary 赋值为零值。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 5 {John Paul 0 0}

访问结构体的字段

点号操作符 . 用于访问结构体的字段。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp6 := Employee{"Sam", "Anderson", 55, 6000}
    fmt.Println("First Name:", emp6.firstName)
    fmt.Println("Last Name:", emp6.lastName)
    fmt.Println("Age:", emp6.age)
    fmt.Printf("Salary: $%d", emp6.salary)
}

上面程序中的 emp6.firstName 访问了结构体 emp6 的字段 firstName。该程序输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
First Name: Sam  
Last Name: Anderson  
Age: 55  
Salary: $6000

还可以创建零值的 struct,以后再给各个字段赋值。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    var emp7 Employee
    emp7.firstName = "Jack"
    emp7.lastName = "Adams"
    fmt.Println("Employee 7:", emp7)
}

在上面程序中,我们定义了 emp7,接着给 firstNamelastName 赋值。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Employee 7: {Jack Adams 0 0}

结构体的指针

还可以创建指向结构体的指针。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp8 := &Employee{"Sam", "Anderson", 55, 6000}
    fmt.Println("First Name:", (*emp8).firstName)
    fmt.Println("Age:", (*emp8).age)
}

在上面程序中,emp8 是一个指向结构体 Employee 的指针。(*emp8).firstName 表示访问结构体 emp8firstName 字段。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
First Name: Sam
Age: 55

Go 语言允许我们在访问 firstName 字段时,可以使用 emp8.firstName 来代替显式的解引用 (*emp8).firstName

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Employee struct {  
    firstName, lastName string
    age, salary         int
}

func main() {  
    emp8 := &Employee{"Sam", "Anderson", 55, 6000}
    fmt.Println("First Name:", emp8.firstName)
    fmt.Println("Age:", emp8.age)
}

在上面的程序中,我们使用 emp8.firstName 来访问 firstName 字段,该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
First Name: Sam
Age: 55

匿名字段

当我们创建结构体时,字段可以只有类型,而没有字段名。这样的字段称为匿名字段(Anonymous Field)。

以下代码创建一个 Person 结构体,它含有两个匿名字段 stringint

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Person struct {  
    string
    int
}

我们接下来使用匿名字段来编写一个程序。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Person struct {  
    string
    int
}

func main() {  
    p := Person{"Naveen", 50}
    fmt.Println(p)
}

在上面的程序中,结构体 Person 有两个匿名字段。p := Person{"Naveen", 50} 定义了一个 Person 类型的变量。该程序输出 {Naveen 50}

虽然匿名字段没有名称,但其实匿名字段的名称就默认为它的类型。比如在上面的 Person 结构体里,虽说字段是匿名的,但 Go 默认这些字段名是它们各自的类型。所以 Person 结构体有两个名为 stringint 的字段。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type Person struct {  
    string
    int
}

func main() {  
    var p1 Person
    p1.string = "naveen"
    p1.int = 50
    fmt.Println(p1)
}

在上面程序中,我们访问了 Person 结构体的匿名字段,我们把字段类型作为字段名,分别为 "string" 和 "int"。上面程序的输出如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{naveen 50}

嵌套结构体(Nested Structs)

结构体的字段有可能也是一个结构体。这样的结构体称为嵌套结构体。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 也是结构体。该程序输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Name: Naveen  
Age: 50  
City: Chicago  
State: Illinois

提升字段(Promoted Fields)

如果是结构体中有匿名的结构体类型字段,则该匿名结构体里的字段就称为提升字段。这是因为提升字段就像是属于外部结构体一样,可以用外部结构体直接访问。我知道这种定义很复杂,所以我们直接研究下代码来理解吧。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type Address struct {  
    city, state string
}
type Person struct {  
    name string
    age  int
    Address
}

在上面的代码片段中,Person 结构体有一个匿名字段 Address,而 Address 是一个结构体。现在结构体 Addresscitystate 两个字段,访问这两个字段就像在 Person 里直接声明的一样,因此我们称之为提升字段。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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.cityp.state,访问提升字段 citystate 就像它们是在结构体 p中声明的一样。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Name: Naveen  
Age: 50  
City: Chicago  
State: Illinois

导出结构体和字段

如果结构体名称以大写字母开头,则它是其他包可以访问的导出类型(Exported Type)。同样,如果结构体里的字段首字母大写,它也能被其他包访问到。

让我们使用自定义包,编写一个程序来更好地去理解它。

在你的 Go 工作区的 src 目录中,创建一个名为 structs 的文件夹。另外在 structs 中再创建一个目录 computer

computer 目录中,在名为 spec.go 的文件中保存下面的程序。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package computer

type Spec struct { //exported struct  
    Maker string //exported field
    model string //unexported field
    Price int //exported field
}

上面的代码片段中,创建了一个 computer 包,里面有一个导出结构体类型 SpecSpec 有两个导出字段 MakerPrice,和一个未导出的字段 model。接下来我们会在 main 包中导入这个包,并使用 Spec 结构体。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import "structs/computer"  
import "fmt"

func main() {  
    var spec computer.Spec
    spec.Maker = "apple"
    spec.Price = 50000
    fmt.Println("Spec:", spec)
}

包结构如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
src  
   structs
        computer
            spec.go
        main.go

在上述程序的第 3 行,我们导入了 computer 包。在第 8 行和第 9 行,我们访问了结构体 Spec 的两个导出字段 MakerPrice。执行命令 go install structsworkspacepath/bin/structs,运行该程序。

如果我们试图访问未导出的字段 model编译器会报错。将 main.go 的内容替换为下面的代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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)
}

在上面程序,我们试图访问未导出的字段 model。如果运行这个程序,编译器会产生错误:spec.model undefined (cannot refer to unexported field or method model)

结构体相等性(Structs Equality)

结构体是值类型。如果它的每一个字段都是可比较的,则该结构体也是可比较的。如果两个结构体变量的对应字段相等,则这两个变量也是相等的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type name struct {  
    firstName string
    lastName string
}


func main() {  
    name1 := name{"Steve", "Jobs"}
    name2 := name{"Steve", "Jobs"}
    if name1 == name2 {
        fmt.Println("name1 and name2 are equal")
    } else {
        fmt.Println("name1 and name2 are not equal")
    }

    name3 := name{firstName:"Steve", lastName:"Jobs"}
    name4 := name{}
    name4.firstName = "Steve"
    if name3 == name4 {
        fmt.Println("name3 and name4 are equal")
    } else {
        fmt.Println("name3 and name4 are not equal")
    }
}

在上面的代码中,结构体类型 name 包含两个 string 类型。由于字符串是可比较的,因此可以比较两个 name 类型的结构体变量。

上面代码中 name1name2 相等,而 name3name4 不相等。该程序会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
name1 and name2 are equal  
name3 and name4 are not equal

如果结构体包含不可比较的字段,则结构体变量也不可比较。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package main

import (  
    "fmt"
)

type image struct {  
    data map[int]int
}

func main() {  
    image1 := image{data: map[int]int{
        0: 155,
    }}
    image2 := image{data: map[int]int{
        0: 155,
    }}
    if image1 == image2 {
        fmt.Println("image1 and image2 are equal")
    }
}

在上面代码中,结构体类型 image 包含一个 map 类型的字段。由于 map 类型是不可比较的,因此 image1image2 也不可比较。如果运行该程序,编译器会报错:main.go:18: invalid operation: image1 == image2 (struct containing map[int]int cannot be compared)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.04.10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
10分钟学会Go结构体类型
结构是表示字段集合的用户定义类型。它可以用于将数据分组为单个单元而不是将每个数据作为单独的值的地方。 例如,员工有firstName、lastName和age。将这三个属性分组到一个名为Employee。
兔云小新LM
2022/11/21
4800
结构体
该程序定义了 emp4,却没有初始化任何值。因此 firstName 和 lastName 赋值为 string 的零值("")。而 age 和 salary 赋值为 int 的零值(0)
酷走天涯
2019/06/11
1.2K0
Golang学习笔记之结构体(struct)
•通俗来说是⼀个与成员类型同名 (不含包名) 的字段。 •被匿名嵌⼊的可以是任何类型,包括指针。 •不能同时嵌⼊某⼀类型和其指针类型,因为它们名字相同。 •匿名字段可以字段提升。可以像普通字段那样访问匿名字段成员,编译器从外向内逐级查找所有层次的匿名字段,直到发现目标或出错。但结构体匿名字段外层同名字段会遮蔽嵌⼊字段成员
李海彬
2018/12/26
6140
100天精通Golang(基础入门篇)——第18天:深入解析Go语言中的结构体
在第18天的学习中,我们将深入探索Go语言中的结构体,这是Go语言中一个非常核心的概念。结构体为我们提供了一种封装多个不同类型数据的方法,是构建复杂数据类型的基础。
猫头虎
2024/04/09
1490
100天精通Golang(基础入门篇)——第18天:深入解析Go语言中的结构体
Golang Struct 声明和使用
Go可以声明自定义的数据类型,组合一个或多个类型,可以包含内置类型和用户自定义的类型,可以像内置类型一样使用struct类型
程序员同行者
2019/01/03
6120
你有对象类,我有结构体,Go lang1.18入门精炼教程,由白丁入鸿儒,go lang结构体(struct)的使用EP06
    再续前文,在面向对象层面,Python做到了超神:万物皆为对象,而Ruby,则干脆就是神:飞花摘叶皆可对象。二者都提供对象类操作以及继承的方式为面向对象张目,但Go lang显然有一些特立独行,因为它没有传统的类,也没有继承,取而代之的是结构和组合的方式,也就是结构体(struct)的方式来组织代码,达到类似类的效果。
用户9127725
2022/09/21
2770
Golang深入浅出之-Go语言结构体(struct)入门:定义与使用
在Go语言的世界中,结构体(struct)作为构建复杂数据类型的基础组件,扮演着至关重要的角色。它允许我们组合多个不同类型的字段,形成一个自定义的数据结构,以更好地模拟现实世界中的实体或概念。本文将深入浅出地探讨Go语言结构体的定义与使用,揭示其中的常见问题、易错点,并提供实用的代码示例及避免方法。
Jimaks
2024/04/25
3470
一篇文章彻底搞懂Go语言中的接口(2)
今天继续上次没写完的Go语言中的接口,上次写了《一篇文章彻底搞懂Go语言中的接口(1)》, 看标题就知道应该还有一篇, 不过这篇也拖得太久了, 再过几天就相隔3个月了。
leoay 技术
2023/06/12
1960
一篇文章彻底搞懂Go语言中的接口(2)
什么是Go struct以及如何编写一个?
在 Go 编程语言 中,结构体(也称为“结构”)是一种复合数据类型,它使将不同类型的值组合到单个实体中成为可能。当您希望将数据分组到单个单元中时,结构体非常方便,而不是必须声明单独的值。
云云众生s
2024/06/22
1230
Golang结构体入门
1.结构体是值类型:在Go语言中,结构体是一种值类型,与数组和基本数据类型一样。当结构体被赋值给一个变量或传递给一个函数时,它的值会被复制一份。因此,对复制的结构体进行修改不会影响原来的结构体。
周小末天天开心
2023/10/16
1870
100天精通Golang(基础入门篇)——第21天:Go语言面向对象(OOP)核心概念解析
Go并没有提供类class,但是它提供了结构体struct,方法method,可以在结构体上添加。提供了捆绑数据和方法的行为,这些数据和方法与类类似。
猫头虎
2024/04/09
1860
虚拟机自动化注意了
使用开源项目:github.com/vmware/govmomi 来实现虚拟机自动化部署流程
heidsoft
2022/01/11
4550
虚拟机自动化注意了
go语言中struct用法
在 Go 语言中,struct 是一种复合数据类型,用于将多个相关的变量组合成一个单一的类型。以下是一些 struct 的用法案例:
周辰晨
2024/09/26
1390
【Go 基础篇】Go语言结构体详解:打开自定义类型的大门
嗨,Go语言学习者们!在编程的世界里,数据是核心,而结构体(Struct)是一种能够帮助我们更有组织地存储和操作数据的重要工具。在本篇博客中,我们将深入探讨Go语言中结构体的概念、定义、初始化、嵌套、方法以及与面向对象编程的关系,带你逐步领略结构体的魅力。
繁依Fanyi
2023/10/12
3490
【Go 基础篇】Go语言结构体详解:打开自定义类型的大门
【Go 基础篇】Go语言结构体基本使用
在Go语言中,结构体是一种重要的数据类型,用于定义和组织一组不同类型的数据字段。结构体允许开发者创建自定义的复合数据类型,类似于其他编程语言中的类。本文将深入探讨Go语言中结构体的定义、初始化、嵌套、方法以及与其他语言的对比,以便全面了解如何在Go中使用结构体。
繁依Fanyi
2023/10/12
2230
【Go 基础篇】Go语言结构体基本使用
go-结构体
Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念。Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。
新人小试
2020/03/09
6250
GoLang读写数据---下
数据结构要在网络中传输或保存到文件,就必须对其编码和解码;目前存在很多编码格式:JSON,XML,gob,Google 缓冲协议等等。Go 语言支持所有这些编码格式;在本节,我们将讨论前三种格式。
大忽悠爱学习
2022/08/23
5840
Golang学习笔记之方法(method)
一个方法只是一个函数,它有一个特殊的接收者(receiver)类型,该接收者放在 func 关键字和函数名之间。接收者可以是结构体类型或非结构体类型。可以在方法内部访问接收者。 一般语法为:
李海彬
2018/12/26
4150
Golang之旅16-嵌套结构体
内容 嵌套结构体 不同的结构体之间的命名冲突 结构体的继承实现 嵌套结构体 一个结构体中可以嵌套包含另一个结构体或结构体指针 package main import "fmt" type Address struct { Provice string //字段名称 字段类型 City string } type User struct { Name string Gender string Address Address //类型是上面的Address类型 } // 结构体的
皮大大
2021/03/02
8530
Golang数据类型之结构体-下篇
c1、c2、c3都是car struct的实例,c2, c3是指向实例的指针,指针中保存的是实例的地址,所以指针再指向实例,c1则是直接指向实例。这三个变量与Car struct实例的指向关系如下
仙人技术
2021/08/31
9120
Golang数据类型之结构体-下篇
推荐阅读
相关推荐
10分钟学会Go结构体类型
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验