Skip to content

Go 结构体

虽然 Go 中的数组(arrays)和切片(slices)存放的是同一种类型的元素,但**结构体(structs)**是用户定义的类型,允许你将可能不同类型的相关数据项组合成一个单一的单元。

结构体对于建模现实世界中的实体或记录非常有用。例如,如果你想表示一本书的信息,你可以将书名(title)、作者(author)、主题(subject)和 ID 等属性组合在一起:

  • 书名 (string)
  • 作者 (string)
  • 主题 (string)
  • 图书ID (int)

你使用 type 和 struct 关键字来定义结构体。type 关键字引入一个新的类型名称,而 struct 则指定这个类型由一系列命名字段组成,每个字段都有自己的类型。

// 定义一个新的结构体类型 'Book'
type Book struct {
Title string // 字段 'Title',类型为 string
Author string // 字段 'Author',类型为 string
Subject string // 字段 'Subject',类型为 string
BookID int // 字段 'BookID',类型为 int
}

定义之后,Book 就成为一个新的类型。你可以声明该类型的变量。

有几种方法可以创建结构体类型的实例(变量):

// 1. 使用 'var' 关键字(字段获得零值)
var book1 Book // book1.Title="",book1.Author="",...,book1.BookID=0
// 2. 使用短变量声明和结构体字面量(推荐)
book2 := Book{
Title: "Go Programming",
Author: "TutorialsPoint",
Subject: "Go Programming Tutorial",
BookID: 6495407,
}
// 3. 不带字段名的结构体字面量(顺序必须与定义匹配 - 可读性差,应避免)
book3 := Book{"Telecom Billing", "Zara Ali", "Telecom Billing Tutorial", 6495700}
// 4. 使用内置函数 'new'(返回指向零值结构体的指针)
bookPtr := new(Book) // bookPtr 的类型是 *Book,指向一个零值的 Book 结构体

你使用点号(.)运算符来访问结构体实例的字段(成员)。

package main
import "fmt"
type Book struct {
Title string
Author string
Subject string
BookID int
}
func main() {
// 使用结构体字面量创建实例
book1 := Book{
Title: "Go Programming",
Author: "TutorialsPoint",
Subject: "Go Programming Tutorial",
BookID: 6495407,
}
book2 := Book{"Telecom Billing", "Zara Ali", "Telecom Billing Tutorial", 6495700}
// 访问并打印 Book1 字段
fmt.Printf("Book 1 Title: %s\n", book1.Title)
fmt.Printf("Book 1 Author: %s\n", book1.Author)
fmt.Printf("Book 1 Subject: %s\n", book1.Subject)
fmt.Printf("Book 1 BookID: %d\n", book1.BookID)
fmt.Println("---")
// 访问并打印 Book2 字段
fmt.Printf("Book 2 Title: %s\n", book2.Title)
fmt.Printf("Book 2 Author: %s\n", book2.Author)
fmt.Printf("Book 2 Subject: %s\n", book2.Subject)
fmt.Printf("Book 2 BookID: %d\n", book2.BookID)
// 修改字段
book1.Author = "Updated Author"
fmt.Printf("\nBook 1 Updated Author: %s\n", book1.Author)
}

输出:

Book 1 Title: Go Programming
Book 1 Author: TutorialsPoint
Book 1 Subject: Go Programming Tutorial
Book 1 BookID: 6495407
---
Book 2 Title: Telecom Billing
Book 2 Author: Zara Ali
Book 2 Subject: Telecom Billing Tutorial
Book 2 BookID: 6495700
Book 1 Updated Author: Updated Author

你可以像传递其他任何类型一样将结构体传递给函数。默认情况下,Go 按值传递参数,这意味着函数接收的是结构体的副本。函数内部的修改不会影响原始结构体。

package main
import "fmt"
type Book struct {
Title string
Author string
Subject string
BookID int
}
// 函数接受一个 Book 结构体(按值传递 - 接收副本)
func printBookInfo(b Book) {
fmt.Printf("Title: %s, Author: %s, ID: %d\n", b.Title, b.Author, b.BookID)
// 在这里修改 'b' 只会改变副本
b.Title = "Changed inside function"
}
func main() {
book1 := Book{
Title: "Go Programming",
Author: "TutorialsPoint",
Subject: "Go Programming Tutorial",
BookID: 6495407,
}
fmt.Println("Printing Book 1:")
printBookInfo(book1) // 传递 book1 的副本
fmt.Printf("Original Book 1 Title after function call: %s\n", book1.Title)
}

输出:

Printing Book 1:
Title: Go Programming, Author: TutorialsPoint, ID: 6495407
Original Book 1 Title after function call: Go Programming

如果你需要一个函数来修改原始结构体,或者出于性能原因想避免复制大型结构体,你应该传递结构体的指针(pointer)。

你可以使用 *TypeName(例如 *Book)声明一个指向结构体的指针。使用 & 运算符获取结构体实例的地址。

var bookPtr *Book // 声明一个指向 Book 的指针
book1 := Book{ ... }
bookPtr = &book1 // 将 book1 的地址赋给 bookPtr

Go 提供了一种方便的简写:你可以使用与结构体值相同的点号(.)表示法通过指针访问结构体的字段。Go 会自动为你解引用(dereference)指针。

bookPtr.Title
// 你可以直接写成 bookPtr.Title,而不是 (*bookPtr).Title

使用指针的示例:

package main
import "fmt"
type Book struct {
Title string
Author string
Subject string
BookID int
}
// 函数接受一个指向 Book 的指针(*Book)
func updateBookTitle(b *Book, newTitle string) {
if b == nil { // 检查 nil 指针是一个好习惯
fmt.Println("Cannot update a nil book pointer")
return
}
// 通过指针修改原始结构体的 Title 字段
b.Title = newTitle // Go 会自动处理 (*b).Title
}
func main() {
book1 := Book{
Title: "Go Programming",
Author: "TutorialsPoint",
Subject: "Go Programming Tutorial",
BookID: 6495407,
}
fmt.Printf("Original Title: %s\n", book1.Title)
// 将 book1 的地址 (&) 传递给函数
updateBookTitle(&book1, "Learning Go Structs")
fmt.Printf("Updated Title: %s\n", book1.Title)
// new() 的示例
bookPtr := new(Book) // 创建一个零值 Book 并返回一个 *Book 指针
updateBookTitle(bookPtr, "Pointer Example")
fmt.Printf("Title from new() pointer: %s\n", bookPtr.Title)
}

输出:

Original Title: Go Programming
Updated Title: Learning Go Structs
Title from new() pointer: Pointer Example