Go:指针和结构体

        Go语言中的指针是一种非常重要的概念,它允许程序员直接访问和操作内存地址,从而可以更高效地管理和传递数据。在Go中,指针相关的知识点主要包括指针的定义、指针的使用、指针与结构体的关系、指针与函数传参等。

一 什么是指针

        在Go语言中,指针是一个保存变量内存地址的变量。通过指针,程序可以直接操作指针所指向的变量。指针的类型是使用*符号表示的,例如*int表示指向整数的指针。学习指针,我们需要牢牢掌握两个符号:&和*。&表示取对象的地址,*表示通过指针访问变量的值,也就是通常说的“解引用”。

        例如,在下面的代码中,我们定义了一个指针变量p,其值等于变量a的地址,当我们直接输出p时,所看到的结果就是变量a在内存中存储的地址,而*p就是获取p指针指向的地址的值。

    // 定义一个变量
	a := 42

	// 获取变量的地址
	p := &a

	// 打印变量的值,指针的值(即地址),和通过指针访问的值
	fmt.Println("Value of a:", a)         
	fmt.Println("Address of a:", p)      
	fmt.Println("Value via pointer:", *p) 

	// 修改指针指向的值
	*p = 100
	fmt.Println("New value of a:", a) 

        运行结果如下:

二 指针的使用

        其实我们刚刚已经使用过指针了,这里我们再系统学习一下指针的使用方式。我们可以通过

var var_name *var-type

 来定义一个指针,例如: var p *int就是一个指向int型数据地址的指针。我们可以使用&来为指针变量赋值,如 p = &a。如果我们定义了一个指针但没有为它分配任何变量,那么该指针的值为 nil,也就是“空指针”。

三 指针的应用

1.结构体

        在Go语言中,指针可以指向结构体,从而可以通过指针操作结构体的字段。通过使用结构体指针,可以避免在函数调用中复制结构体数据,从而提高效率。

package main

import (
	"fmt"
)

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

func main() {
	// 创建结构体的实例
	p := &Person{Name: "Alice", Age: 30}

	// 通过指针访问结构体字段
	fmt.Println("Name:", p.Name) // 输出:Name: Alice
	fmt.Println("Age:", p.Age)   // 输出:Age: 30

	// 修改结构体字段的值
	p.Age = 31
	fmt.Println("New Age:", p.Age) // 输出:New Age: 31
}

2.函数

        在Go语言中,函数参数是按值传递的,这意味着函数接收到的是参数的副本。如果希望函数能够修改传入的变量值,则需要使用指针作为参数传递。 

package main

import (
	"fmt"
)

func increment(x *int) {
	*x = *x + 1
}

func main() {
	a := 10
	fmt.Println("Before increment:", a) // 输出:Before increment: 10

	// 传递指针给函数
	increment(&a)

	fmt.Println("After increment:", a) // 输出:After increment: 11
}

四 结构体的定义和使用

        Go语言中的结构体(Struct)是一种用户自定义的数据类型,它将不同类型的值组合在一起,形成一个新的复合数据类型。结构体在Go语言中广泛用于组织数据,并可以为其定义方法,使其具备一定的行为能力,相当于其他编程语言中的“类”(但Go不支持类继承),是面向对象编程的基础。

        在Go语言中,结构体通过struct关键字定义。结构体的定义包括结构体的名称和它所包含的字段,每个字段都有自己的名称和类型。

package main

import (
	"fmt"
)

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

        我们可以通过多种方式进行初始化,初始化时忽略的字段为 0 或 空:

    var p Person
	p.Name = "Alice"
	p.Age = 30
	p.City = "New York"
	fmt.Println(p) // 输出:{Alice 30 New York}

	p1 := Person{Name: "Bob", Age: 25, City: "San Francisco"}
	fmt.Println(p1) // 输出:{Bob 25 San Francisco}

	p2 := &Person{Name: "Charlie", Age: 35, City: "Los Angeles"}
	fmt.Println(*p2) // 输出:{Charlie 35 Los Angeles}

	p3 := Person{"Lucy", 22, "123"}
	fmt.Println(p3) // 输出:{Lucy 22 123}

	p4 := Person{Name: "Bob", Age: 25}
	fmt.Println(p4) // 输出:{Bob 25 }

        结构体字段的访问和修改可以通过点运算符.来进行,例如:

    p.Name = "July"
	fmt.Println("Name:", p.Name) // 输出:Name: July

五 结构体的嵌套与匿名字段

        结构体可以嵌套使用,这意味着一个结构体可以包含另一个结构体作为它的字段。

type Address struct {
	City, State string
}

type Person struct {
	Name    string
	Age     int
	Address Address
}

func main() {
	p := Person{
		Name: "David",
		Age:  40,
		Address: Address{
			City:  "Miami",
			State: "Florida",
		},
	}

	fmt.Println(p)                  // 输出:{David 40 {Miami Florida}}
	fmt.Println(p.Address.City)     // 输出:Miami
	fmt.Println(p.Address.State)    // 输出:Florida
}

        此外,Go语言支持匿名字段,这种方式允许在结构体中嵌入一个未命名的结构体,使其字段可以直接访问。 

type Address struct {
	City, State string
}

type Person struct {
	Name string
	Age  int
	Address // 匿名嵌入结构体
}

func main() {
	p := Person{
		Name: "Eve",
		Age:  28,
		Address: Address{
			City:  "Boston",
			State: "Massachusetts",
		},
	}

	fmt.Println(p)        // 输出:{Eve 28 {Boston Massachusetts}}
	fmt.Println(p.City)   // 直接访问匿名字段的字段,输出:Boston
	fmt.Println(p.State)  // 直接访问匿名字段的字段,输出:Massachusetts
}

六 结构体方法

        在Go语言中,可以为结构体定义方法。方法是一个特殊的函数,它的第一个参数是接收者(Receiver),用于指定这个方法是哪个结构体的。这使得结构体可以有自己的行为,类似于面向对象编程中的类方法。

package main

import (
	"fmt"
)

// 定义结构体
type Rectangle struct {
	Width, Height int
}

// 为结构体定义方法
func (r Rectangle) Area() int {
	return r.Width * r.Height
}

// 通过指针接收者修改结构体字段
func (r *Rectangle) Scale(factor int) {
	r.Width *= factor
	r.Height *= factor
}

func main() {
	rect := Rectangle{Width: 10, Height: 5}

	// 调用方法
	area := rect.Area()
	fmt.Println("Area:", area) // 输出:Area: 50

	// 调用方法修改结构体字段
	rect.Scale(2)
	fmt.Println("Scaled Rectangle:", rect) // 输出:Scaled Rectangle: {20 10}
}

七 结构体的比较

        Go语言中的结构体可以直接进行比较,前提是所有的字段都可以比较(即字段类型本身可以使用==!=进行比较)。

package main

import (
	"fmt"
)

type Point struct {
	X, Y int
}

func main() {
	p1 := Point{X: 1, Y: 2}
	p2 := Point{X: 1, Y: 2}
	p3 := Point{X: 2, Y: 3}

	fmt.Println(p1 == p2) // 输出:true
	fmt.Println(p1 == p3) // 输出:false
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值