Menu
CoddyTech

指向结构体的指针

本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 20 课,共 107 课。

处理结构体时,你通常会使用指针来避免复制大型数据结构,并修改原始结构体。指向结构体的指针保存着该结构体实例的内存地址。

你可以对现有结构体使用 & 运算符来创建结构体指针,也可以直接对结构体字面量使用取地址运算符。

type Person struct {
    Name string
    Age  int
}

p := Person{Name: "Alice", Age: 30}
ptr := &p  // 指向已有结构体的指针

// 或者直接创建
ptr2 := &Person{Name: "Bob", Age: 25}

通过指针访问结构体字段时,Go 提供了一种方便的简写方式。不必写 (*ptr).Name,你只需写 ptr.Name。Go 会自动为你解引用指针。

ptr := &Person{Name: "Alice", Age: 30}

// 两种写法效果相同
fmt.Println((*ptr).Name)  // 显式解引用
fmt.Println(ptr.Name)     // 自动解引用

修改字段时也会自动解引用。通过指针所做的更改会影响原始结构体。

p := Person{Name: "Alice", Age: 30}
ptr := &p

ptr.Age = 31           // 修改原始对象
fmt.Println(p.Age)     // 31

结构体指针是 Go 面向对象编程模式的重要组成部分。它们可以让方法修改接收者状态,让大型结构体高效地传递给函数,并为构建树和链表等链式数据结构奠定基础。

challenge icon

挑战

简单

让我们构建一个银行账户系统,演示结构体指针如何高效地修改原始数据。你将创建一个账户,并通过指针操作更新账户信息。

你将把代码分成两个文件:

  • account.go:定义一个 BankAccount 结构体,包含 Owner(string)、Balance(float64)和 AccountNumber(string)字段。创建一个名为 NewAccount 的函数,它接收账户所有者姓名和账户号码作为参数,并返回一个指向新建 BankAccount 的指针,初始余额为 0。再创建一个 Deposit 函数,它接收一个 *BankAccount 指针和一笔金额,然后通过指针将这笔金额加到账户余额中。
  • main.go:从输入中读取账户信息,使用构造函数(该函数会返回一个指针)创建账户,通过指针存入一笔金额,并显示账户详情,以确认余额已修改。

将提供以下输入:

  • 第 1 行:账户所有者姓名
  • 第 2 行:账户号码
  • 第 3 行:存款金额(浮点数)

输出格式:

Account: [AccountNumber]
Owner: [Owner]
Balance: [Balance]

例如,给定 John Smith、ACC-12345 和 500.50,你的输出应为:

Account: ACC-12345
Owner: John Smith
Balance: 500.50

请记住,NewAccount 函数应使用 & 运算符返回 *BankAccount,而 Deposit 函数可以使用 Go 的自动解引用功能,通过指针直接修改余额(例如,使用 account.Balance,而不是 (*account).Balance)。

亲手试试

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// 读取账户所有者姓名
	ownerName, _ := reader.ReadString('\n')
	ownerName = strings.TrimSpace(ownerName)
	
	// 读取账号
	accountNumber, _ := reader.ReadString('\n')
	accountNumber = strings.TrimSpace(accountNumber)
	
	// 读取存款金额
	amountStr, _ := reader.ReadString('\n')
	amountStr = strings.TrimSpace(amountStr)
	amount, _ := strconv.ParseFloat(amountStr, 64)
	
	// TODO:使用 NewAccount 函数创建新账户(返回一个指针)
	
	// TODO:使用账户指针调用 Deposit 函数进行存款
	
	// TODO:按要求的格式输出账户详情:
	// 账户:[AccountNumber]
	// 所有者:[Owner]
	// 余额:[Balance]
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Go 在线编译器