自学内容网 自学内容网

go语言中的结构体详解

1.概念

在Go语言中,结构体是一种自定义的数据类型,用于将不同类型的字段组合在一起形成一个新的数据结构。结构体定义了一组字段,每个字段可以有不同的类型,这些字段一起构成了结构体的实例。通过结构体,我们可以将相关的数据进行组织和管理,从而更方便地进行操作和传递。

结构体的定义使用关键字typestruct。以下是结构体的定义语法:

type 结构体名称 struct {
    字段1 类型1
    字段2 类型2
    // 更多字段...
}

1.1基本用法

type User struct {
    Name string
    Age  int
    Address string
}

首先,可以使用结构体字面量直接初始化结构体变量,按照字段顺序给出对应的值。示例如下:

person := Person{"Alice", 25, "广东深圳"}

 其次可以使用指定字段名的方式给出字段的初始化值,这个时候可以忽略某些字段。示例如下:

person := Person{Name: "Alice", Age: 25}

也可以使用new关键字创建一个指向结构体的指针,并返回该指针。示例如下:

personPtr := new(Person)
personPtr.Name = "Alice"
personPtr.Age = 25

 下面定义了结构体的基本用法:

package main

import "fmt"

// 定义结构体
type Person struct {
    Name string
    Age  int
}

// 定义方法:打印个人信息
func (p Person) PrintInfo() {
    fmt.Printf("Name: %s\n", p.Name)
    fmt.Printf("Age: %d\n", p.Age)
}

// 定义方法:修改年龄
func (p Person) UpdateAge(newAge int) {
    p.Age = newAge
}

func main() {
    // 创建一个 Person 结构体实例
    person := Person{Name: "John", Age: 30}
    // 调用结构体的方法:打印个人信息
    person.PrintInfo() // Output: Name: John   Age: 30
    // 调用结构体的方法:修改年龄
    person.UpdateAge(35)
    // 再次调用方法,打印修改后的个人信息
    person.PrintInfo() // Output: Name: John   Age: 35
}

运行结果:

2.结构体的可见性 

结构体在Go语言中支持数据可见性的特性。其通过首字母大小写可以限制结构体字段和方法的可见性,从而实现信息的隐藏和封装。

在结构体中,方法名或者字段名,其首字母大写,代表着对外是可见和可修改的;首字母小写,则代表着对外为不可见的。如果想要读取或者修改,只能通过对外暴露的接口来进行,通过这种方式,可以隐藏结构体的内部实现细节,同时确保对结构体数据的访问和操作通过封装的公开方法进行,提供了更好的安全性和封装性。下面给出一个代码的示例:

package main

import "fmt"

// 定义结构体
type Person struct {
    name string // 私有字段
}

// 定义公开方法:设置姓名
func (p *Person) SetName(name string) {
    p.name = name
}

// 定义公开方法:获取姓名
func (p *Person) GetName() string {
    return p.name
}

func main() {
    // 创建一个 Person 结构体实例
    person := Person{}
    // 这里将无法通过编译
    // person.name = "hello eva"
    // 通过公开方法设置姓名和年龄
    person.SetName("John")
    // 通过公开方法获取姓名和年龄并打印
    fmt.Println("Name:", person.GetName()) // Output: Name: John

}

•  首字母大写:如果结构体的字段名首字母是大写的(例如 Name),那么这个字段在包外也是可见的,即它是公开的(exported)。
•  首字母小写:如果结构体的字段名首字母是小写的(例如 name),那么这个字段只在定义它的包内可见,即它是非公开的(unexported)。 

 在这个例子中,Name 字段是公开的,可以在包外访问。而 age 字段是非公开的,只能在定义它的包内访问。 

为了提供对非公开字段的控制访问,通常会在结构体上定义方法。这些方法可以是公开的,但它们操作的是私有字段。

package main

import "fmt"

type Person struct {
    Name string // 公开字段
    age  int    // 非公开字段
}

// 方法 SetAge 允许外部代码设置年龄,但保持 age 字段的私有性
func (p *Person) SetAge(a int) {
    if a >= 0 {
        p.age = a
    }
}

// 方法 GetAge 允许外部代码获取年龄
func (p *Person) GetAge() int {
    return p.age
}

func main() {
    p:=Person{Name:"Alice"}
p.SetAge(30)
fmt.Println(p.Name,p.GetAge())
}

 

 3 结构体能够实现接口

接口定义了一组方法的契约,描述了这些方法的行为和签名。

在Go语言中,接口是一种类型,由一组方法签名组成。一个结构体可以实现该接口中的所有方法,此时可以认为其实现了该接口,从而可以以相同的方式被使用。这种特性提供了多态性,允许我们编写通用的代码,适用于多种类型的结构体。以下是一个示例,演示了结构体如何实现一个接口:

步骤:

  • 1.  定义接口:首先定义一个接口,指定需要实现的方法。
  • 2.  定义结构体:定义一个结构体类型。
  • 3.  实现方法:为结构体添加方法,方法的接收者是结构体的指针或值。
  • 4.  接口赋值:可以将实现了接口的结构体赋值给接口类型的变量。 
package main

import "fmt"

// 定义接口
type Shape interface {
    Area() float64
    Perimeter() float64
}

// 定义矩形结构体
type Rectangle struct {
    Width  float64
    Height float64
}

// 实现接口方法:计算矩形的面积
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

// 实现接口方法:计算矩形的周长
func (r Rectangle) Perimeter() float64 {
    return 2 * (r.Width + r.Height)
}

func main() {
    // 创建一个矩形结构体实例
    rectangle := Rectangle{Width: 5, Height: 3}

    // 将矩形实例赋值给接口变量
    var shape Shape
    shape = rectangle

    // 通过接口调用方法,计算面积和周长
    area := shape.Area()
    perimeter := shape.Perimeter()

    fmt.Println("Area:", area)           // Output: Area: 15
    fmt.Println("Perimeter:", perimeter) // Output: Perimeter: 16
}

4.匿名字段

在Go语言中,匿名字段是一种特殊的字段,它允许一个结构体嵌入另一个结构体的字段,而不需要显式地命名这个嵌入的结构体。这样,嵌入的结构体的字段就可以直接通过外层结构体访问,就好像它们是外层结构体的直接字段一样。

 匿名字段的作用

1. 代码复用:允许在不同的结构体中重用相同的字段。

2. 接口实现:通过嵌入接口,可以使一个结构体隐式地实现该接口。

3. 继承:虽然Go不支持传统的继承,但通过嵌入可以模拟继承的效果。

package main

import "fmt"

// 定义一个基本的个人信息结构体
type Person struct {
    Name string
    Age  int
}

// 定义一个包含联系信息的结构体
type ContactInfo struct {
    Email  string
    Phone  string
}

// 定义一个Employee结构体,它嵌入了Person和ContactInfo
type Employee struct {
    Person      // 匿名字段,Person的字段将直接可用
    ContactInfo // 另一个匿名字段
    JobTitle    string
}

func main() {
    // 创建一个Employee实例
    emp := Employee{
        Person: Person{
            Name: "Kimi",
            Age:  30,
        },
        ContactInfo: ContactInfo{
            Email:  "kimi@moonshot.cn",
            Phone:  "1234567890",
        },
        JobTitle: "AI Assistant",
    }

    // 访问嵌入结构体的字段
    fmt.Println("Employee Name:", emp.Name)       // 输出: Employee Name: Kimi
    fmt.Println("Employee Age:", emp.Age)         // 输出: Employee Age: 30
    fmt.Println("Employee Email:", emp.Email)     // 输出: Employee Email: kimi@moonshot.cn
    fmt.Println("Employee Phone:", emp.Phone)     // 输出: Employee Phone: 1234567890
    fmt.Println("Employee Job Title:", emp.JobTitle) // 输出: Employee Job Title: AI Assistant
}

  Person 和 ContactInfo 是两个独立的结构体。

 Employee 结构体通过匿名字段嵌入了 Person 和 ContactInfo。这意味着 Employee 的实例可以直接访问 Person 和 ContactInfo 的所有字段。

 在创建 Employee 的实例时,可以直接初始化嵌入的 Person 和 ContactInfo 的字段。

这种使用匿名字段的方式使得代码更加简洁和易于管理,同时也提高了代码的复用性。

5.new函数

在Go语言中,结构体是一种自定义的数据类型,它允许你将多个不同类型的数据项组合成一个类型。结构体通常用于表示复杂的数据结构。
new 关键字在Go语言中用于分配内存。当你使用 new 来创建一个结构体实例时,它会分配足够的内存来存储结构体的字段,并将所有的字段初始化为该类型的零值。

下面是一个使用 new 关键字创建结构:

package main

import "fmt"

// 定义一个结构体类型
type Person struct {
    Name string
    Age  int
}

func main() {
    // 使用 new 分配内存
    p := new(Person)

    // 输出结构体的初始状态
    fmt.Println("Before setting values:")
    fmt.Printf("%+v\n", p)

    // 设置结构体的字段
    p.Name = "Alice"
    p.Age = 30

    // 输出结构体的当前状态
    fmt.Println("After setting values:")
    fmt.Printf("%+v\n", p)
}

 在这个例子中,new(Person) 创建了一个 Person 类型的实例 p,并且所有的字段都被初始化为零值(对于字符串是空字符串,对于整数是0)。然后,你可以设置这些字段的值。
需要注意的是,new 关键字返回的是指针,指向新分配的内存。如果你需要一个值而不是指针,你可以使用 & 操作符来获取指针指向的值,或者        使用 var 关键字来直接创建一个值类型的实例:
p := Person{Name: "Alice", Age: 30} // 使用 var 创建,一个值类型的实例在这种情况下,p 是一个 Person 类型的值,而不是指针。

6.指针结构体

在Go语言中,指针和结构体是两个核心概念,它们经常一起使用,尤其是在处理大型数据结构时。使用指针可以提高程序的性能,尤其是在处理大型结构体时,因为指针允许你直接操作数据而不是数据的副本。

指针和结构体的基本概念

1.  指针:在Go中,指针是一个变量,它存储了另一个变量的内存地址。使用指针可以避免在函数调用时复制整个数据结构,从而节省内存和时间。
2.  结构体:结构体是Go中一种自定义的数据类型,它允许你将多个不同类型的数据项组合成一个单一的数据结构。
使用指针操作结构体
当你有一个结构体类型的变量时,你可以获取它的指针,然后通过这个指针来访问和修改结构体的字段。

创建结构体指针

你可以使用 new 或 & 操作符来创建一个结构体的指针:

个结构体的指针:
type Person struct {
    Name string
    Age  int
}

func main() {
    // 使用 new 创建指针
    p := new(Person)
    p.Name = "Alice"
    p.Age = 30

    // 使用 & 获取变量的地址
    var person Person
    personPointer := &person
    personPointer.Name = "Bob"
    personPointer.Age = 25

    fmt.Println(*p)  // 输出: {Alice 30}
    fmt.Println(person)  // 输出: {Bob 25}
}

在这个例子中,new(Person) 创建了一个 Person 类型的实例,并返回了指向这个实例的指针。&person 获取了 person 变量的地址,即它的指针。

通过指针访问和修改结构体字段
你可以通过指针访问和修改结构体的字段。使用指针访问字段时,使用 . 操作符:

(*p).Name = "Charlie" // 通过指针修改结构体字段
fmt.Println(p)  // 输出: &{Charlie 30}

这里 (*p).Name 表示先对指针 p 解引用,然后访问 Name 字段。

使用指针结构体的好处包括:

1.  性能:传递指针比传递整个结构体更高效,尤其是在结构体很大时。
2.  直接修改:通过指针,你可以在函数内部直接修改原始数据,而不需要返回修改后的结构体。
3.  接口实现:在Go中,接口通常要求方法接收者是指针,以允许修改接口的实现。

 


原文地址:https://blog.csdn.net/2302_79993788/article/details/142342264

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!