结构体和指针

Golang是一种静态类型、编译型的语言,它提供了结构体和指针这两个重要的概念。本文将详细介绍这两个概念及其在Golang中的应用。

结构体

Golang中的结构体类似于C语言中的结构体,但具有更多的功能。结构体是一种自定义数据类型,它由一组字段组成。每个字段都有一个名称和类型,并且可以存储不同类型的数据。

结构体的定义

结构体使用type关键字声明,其语法如下:

type structName struct {
    field1 type1
    field2 type2
    ...
}

其中,structName是结构体名称;field1field2等是字段名称;type1type2等是字段类型。

例如,我们可以创建一个名为Person的结构体,它有三个字段nameageaddress

type Person struct {
    name    string
    age     int
    address string
}

在上面的代码中,我们创建了一个名为Person的结构体,并定义了三个字段nameageaddress

结构体的初始化

我们可以使用以下两种方式来初始化结构体:

字面量初始化

字面量初始化是通过直接指定结构体字段的值来创建结构体的实例。例如:

person := Person{
    name:    "Tom",
    age:     18,
    address: "Beijing",
}

在上面的代码中,我们创建了一个名为person的结构体实例,并为其指定了三个字段的值。

零值初始化

如果没有为结构体的字段显式指定初始值,则会使用默认值进行初始化。默认值是该类型的零值,对于字符串类型是空字符串,对于数值类型是0、对于布尔类型是false等。例如:

var person Person

在上面的代码中,我们创建了一个名为person的结构体实例,并使用零值进行初始化。

访问结构体的字段

结构体的字段可以使用点.操作符来访问。例如:

fmt.Println(person.name)

在上面的代码中,我们使用点.操作符来访问person结构体的name字段。

结构体的嵌套

Golang中的结构体可以嵌套在其他结构体中,从而形成更复杂的数据结构。嵌套结构体的字段可以通过多次使用点.操作符来访问。

例如,假设我们有两个结构体AddressPerson,其中Person结构体包含一个Address结构体作为其字段:

type Address struct {
    street string
    city   string
}

type Person struct {
    name    string
    age     int
    address Address
}

在上面的代码中,我们创建了一个名为Address的结构体和一个名为Person的结构体,并将Address结构体嵌套在Person结构体中。

我们可以使用以下方式来访问嵌套结构体的字段:

person := Person{
    name: "Tom",
    age:  18,
    address: Address{
        street: "Main St.",
        city:   "Beijing",
    },
}

fmt.Println(person.address.city)

在上面的代码中,我们创建了一个名为person的结构体实例,并使用点.操作符来访问其中的address结构体和其字段city

指针

Golang中的指针是一种变量,它存储了另一个变量的内存地址。指针允许程序员通过引用间接访问变量,从而改变其状态。指针是Golang中非常重要的概念,它们用于在函数之间传递数据、动态分配内存等。

指针的声明

Golang中的指针使用*号来声明,其语法如下:

var ptr *type

其中,ptr是指针变量名称;type是指向的变量类型。

例如,我们可以创建一个名为ptr的整数指针:

var ptr *int

在上面的代码中,我们创建了一个名为ptr的整数指针,并将其初始化为nil。

指针的操作符

Golang中有两个操作符与指针相关。

取地址操作符&

取地址操作符&用于获取变量的内存地址。例如:

var a int = 10
var ptr *int = &a

在上面的代码中,我们创建了一个名为a的整数变量,并使用取地址操作符&获取了其内存地址,并将其赋值给了指针变量ptr

解引用操作符*

解引用操作符*用于访问指针所指向的变量的值。例如:

var a int = 10
var ptr *int = &a
fmt.Println(*ptr)

在上面的代码中,我们创建了一个名为a的整数变量,并使用取地址操作符&获取了其内存地址,并将其赋值给了指针变量ptr。然后,我们使用解引用操作符*访问ptr所指向的变量a的值,并打印出来。

指针作为函数参数

指针在Golang中经常用作函数参数,这是因为它们可以允许函数修改其调用者传递的变量的值。这非常有用,特别是在处理大型数据结构时。

例如,我们可以编写一个函数来交换两个整数变量的值:

func swap(x *int, y *int) {
    temp := *x
    *x = *y
    *y = temp
}

func main() {
    a, b := 10, 20
    fmt.Printf("Before swap: a=%d, b=%d\n", a, b)
    swap(&a, &b)
    fmt.Printf("After swap: a=%d, b=%d\n", a, b)
}

在上面的代码中,我们定义了一个名为swap的函数,它接受两个整数指针作为参数,并使用解引用操作符*来交换它们所指向的变量的值。

然后,在main函数中,我们创建了两个整数变量ab,并将它们的值打印出来。接下来,我们调用了swap函数来交换ab的值,并再次打印它们的值。

指针和结构体

结构体也可以通过指针来访问和修改其字段的值。这是因为结构体实际上是一个连续的内存块,而指针可以指向该内存块的起始地址。

例如,我们可以编写一个函数来更改Person结构体变量的名字:

func changeName(person *Person, name string) {
    person.name = name
}

func main() {
    person := Person{
        name: "Tom",
        age:  18,
    }
    fmt.Printf("Before change: %v\n", person)
    changeName(&person, "Jerry")
    fmt.Printf("After change: %v\n", person)
}

在上面的代码中,我们定义了一个名为changeName的函数,它接受一个Person结构体的指针和一个新的名字,并使用点.操作符来访问Person结构体的name字段,并将其修改为新的名字。

然后,在main函数中,我们创建了一个名为personPerson结构体实例,并将其打印出来。接下来,我们调用changeName函数,并传递person结构体的指针和一个新的名字作为参数。最后,我们再次打印person结构体,以验证是否已成功更改其名称。

指针和数组

在Golang中,数组名本身就是指向数组起始位置的指针。因此,指针可以用于访问并操作数组的元素。

例如,我们可以编写一个函数来对整数数组进行排序:

func sortArray(arr *[5]int) {
    for i := 0; i < len(*arr)-1; i++ {
        for j := i + 1; j < len(*arr); j++ {
            if (*arr)[j] < (*arr)[i] {
                tmp := (*arr)[i]
                (*arr)[i] = (*arr)[j]
                (*arr)[j] = tmp
            }
        }
    }
}

func main() {
    arr := [5]int{3, 2, 5, 4, 1}
    fmt.Printf("Before sort: %v\n", arr)
    sortArray(&arr)
    fmt.Printf("After sort: %v\n", arr)
}

在上面的代码中,我们定义了一个名为sortArray的函数,它接受一个整数数组的指针,并使用解引用操作符*来访问数组元素并进行排序。

然后,在main函数中,我们创建了一个名为arr的整数数组,并将其打印出来。接下来,我们调用sortArray函数,并传递arr数组的指针作为参数。最后,我们再次打印已排序的arr数组。

总结

本文介绍了Golang中的结构体和指针的概念及其应用。结构体是一种自定义数据类型,由一组字段组成,并用于表示复杂的数据结构。指针是一种变量,它存储了另一个变量的内存地址,并用于在函数之间传递数据、动态分配内存等。指针可以与结构体、数组等数据类型一起使用,以实现更高效、可维护和可重用的代码。

本主题指南

技术实践与开发文档
  • 为了给wordpress的ripro主题资源站填充数据,我用golang开发了并发版爬虫和分布式爬虫两个版本,已经顺利跑通!

    为了给wordpress的ripro主题资源站填充数据,我用golang开发了并发版爬虫和分布式爬虫两个版本,已经顺利跑通!代码总量还是比较多了,具体课程中再详细讲解,这篇文章主要分享一下自己的技术选型思路,以及我觉得做这个项目过程中自己的一些感悟!包括对于系统架构的理解以及对于golang语言本身的理解。

  • 你所不知道的golang高级用法
  • 在aws上以lambda方式部署golang应用 -(上)用.zip压缩文件部署Go Lambda functions

    在使用 AWS Lambda 运行 Go 时,可以将代码打包成 .zip 文件并上传到 Lambda 上。这样做的好处是可以将所有的依赖项打包在一个文件中,而不需要在 Lambda 中安装它们。同时,也可以避免在多个文件之间进行部署和管理的复杂性。 要将 Go Lambda 函数打包为 .zip 文件,您需要将函数代码和依赖关系放置在一个文件夹中,并将其压缩为 .zip 格式。如果您的 Go 程序包含外部依赖项,则需要在函数代码中包括它们,或者将它们一起打包到 .zip 文件中。 一旦您已经打包了 Lambda 函数,就可以通过 AWS 控制台或 AWS CLI 将其上传到 Lambda。上传完成后,您可以测试该函数并将其发布到您的应用程序中。通过使用 .zip 文件打包 Lambda 函数,可以有效地简化部署和管理过程,使您的开发工作更加高效。

  • 使用golang部署运行tls的https服务时,不用停机,高效证书下放,如何实现?

    在网络通信中,HTTP和HTTPS是常用的应用层协议,而四层服务传输协议和七层服务传输协议则是不同的协议模型。当使用 golang 语言部署和运行带有 TLS 的 HTTPS 服务时,需要采取一些技巧来实现高效证书下放,而不会影响线上服务的正常运行。 HTTP和HTTPS是两种不同的应用层协议,HTTP协议是未加密的、明文传输的,而HTTPS是基于TLS/SSL协议的安全版本,通过加密与认证保护数据传输的安全性。在实际应用中,为了保护用户信息的安全,通常使用HTTPS协议进行网络通信。 四层服务传输协议和七层服务传输协议是不同的协议模型,分别定义了网络通信的逻辑结构和规则。四层服务传输协议(如TCP和UDP)负责在不同主机之间建立端到端的通信连接,并提供可靠的数据传输、流量控制等功能;而七层服务传输协议(如HTTP、SMTP、FTP等)定义了应用程序之间的通信规则、格式和内容,提供特定的服务功能。 Golang是一门开源的编程语言,具有高效性能和良好的并发处理能力。在使用Golang部署和运行TLS的HTTPS服务时,可以采用一些技巧来实现高效证书下放,而不会影响线上服务的正常运行。比如通过使用ACME协议自动化管理证书、使用GRPC框架进行交互式的证书下载等方式,可以有效解决证书下放的问题,并提高系统性能和可靠性。 综上所述,HTTP、HTTPS、四层服务传输协议、七层服务传输协议、Golang、Go语言学习以及Go语言技巧都是网络通信和编程中非常重要的概念和关键词。在进行相关学习和实践时,需要注重理解和掌握这些内容,才能更好地应对实际需求和挑战。

Avatar

Aisen

Be water,my friend.