结构体
在 Golang 中,结构体(struct)是一种复合数据类型,它将多个不同类型的字段组合在一起。结构体用于表示具有多个属性的复杂数据类型。
package main
import "fmt"
type user struct {
name string
password string
}
func main() {
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
fmt.Println(a, b, c, d) // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
fmt.Println(checkPassword(a, "haha")) // false
fmt.Println(checkPassword2(&a, "haha")) // false
}
func checkPassword(u user, password string) bool {
return u.password == password
}
func checkPassword2(u *user, password string) bool {
return u.password == password
}
结构体定义
type user struct {
name string
password string
}
- 定义结构体: 使用
type关键字定义一个名为user的结构体。 - 字段: 结构体包含两个字段:
name和password,它们的类型都是string。
结构体初始化
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
- 完整初始化: 使用键值对的方式初始化结构体
a,指定所有字段的初始值。 - 简写初始化: 直接提供字段值初始化结构体
b,字段顺序必须与定义顺序一致。 - 部分初始化: 使用键值对的方式初始化结构体
c,只初始化部分字段,未初始化的字段会使用零值。 - 零值初始化: 声明结构体变量
d,未初始化的字段会使用零值,然后逐个字段赋值。
结构体指针
func checkPassword2(u *user, password string) bool {
return u.password == password
}
- 指针参数: 函数
checkPassword2接受一个user结构体的指针参数u。 - 指针传递: 通过传递指针,可以在函数中修改结构体的字段,避免大结构体的拷贝开销。
在 main 函数中调用 checkPassword2 函数:
fmt.Println(checkPassword2(&a, "haha")) // false
- 传递指针: 使用
&获取结构体变量a的地址,传递给函数checkPassword2。
总结
- 结构体定义: 结构体是带类型字段的集合,用于表示复杂数据类型。
- 结构体初始化: 可以使用键值对或简写方式初始化结构体,未初始化的字段会使用零值。
- 结构体指针: 通过传递结构体指针,可以在函数中修改结构体的字段,避免大结构体的拷贝开销。
结构体方法
在 Golang 中,可以为结构体定义方法,这类似于其他编程语言中的类成员函数。通过为结构体定义方法,可以更方便地操作结构体实例。
package main
import "fmt"
type user struct {
name string
password string
}
// checkPassword 方法用于检查用户密码是否匹配
func (u user) checkPassword(password string) bool {
return u.password == password
}
// resetPassword 方法用于重置用户密码
func (u *user) resetPassword(password string) {
u.password = password
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
}
定义结构体方法
在 Golang 中,可以为结构体定义方法。方法的定义与普通函数类似,但需要在函数名称前面加上接收者(receiver)。接收者可以是值类型或指针类型。
func (u user) checkPassword(password string) bool {
return u.password == password
}
- 接收者:
u user是方法的接收者,表示该方法属于user结构体。 - 调用方法: 可以通过结构体实例调用该方法,例如
a.checkPassword("2048")。
值接收者与指针接收者
在实现结构体方法时,可以选择使用值接收者或指针接收者。它们的区别在于是否可以修改结构体实例的字段。
值接收者
func (u user) checkPassword(password string) bool {
return u.password == password
}
- 值接收者: 方法接收者是结构体的值副本,对副本的修改不会影响原始结构体实例。
- 用途: 适用于不需要修改结构体实例的场景。
指针接收者
func (u *user) resetPassword(password string) {
u.password = password
}
- 指针接收者: 方法接收者是结构体的指针,可以修改结构体实例的字段。
- 用途: 适用于需要修改结构体实例的场景。
示例代码中的方法
在示例代码中,定义了两个方法:checkPassword 和 resetPassword。
func (u user) checkPassword(password string) bool {
return u.password == password
}
- checkPassword 方法: 使用值接收者,不会修改结构体实例。
func (u *user) resetPassword(password string) {
u.password = password
}
- resetPassword 方法: 使用指针接收者,可以修改结构体实例的字段。
在 main 函数中调用这两个方法:
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // true
}
- 调用 resetPassword 方法: 修改结构体实例
a的password字段。 - 调用 checkPassword 方法: 检查修改后的密码是否匹配。
总结
- 结构体方法: 可以为结构体定义方法,类似于类的成员函数。
- 接收者: 方法的接收者可以是值类型或指针类型。
- 值接收者: 方法接收者是结构体的值副本,对副本的修改不会影响原始结构体实例。
- 指针接收者: 方法接收者是结构体的指针,可以修改结构体实例的字段。
错误处理
在 Golang 中,错误处理的惯用做法是使用一个单独的返回值来传递错误信息。与 Java 等语言使用的异常机制不同,Golang 的错误处理方式更加直接和清晰,可以通过简单的 if-else 语句来处理错误。
package main
import (
"errors"
"fmt"
)
type user struct {
name string
password string
}
func findUser(users []user, name string) (v *user, err error) {
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
func main() {
u, err := findUser([]user{{"wang", "1024"}}, "wang")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) // wang
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
}
错误类型
在 Golang 中,错误类型是内置的 error 接口。可以通过实现 Error 方法来创建自定义错误类型。标准库中的 errors 包提供了创建错误的简单方法。
import "errors"
- 创建错误: 使用
errors.New函数创建一个新的错误。
函数返回错误
在函数定义中,可以在返回值类型列表中添加 error 类型,表示该函数可能会返回错误。
func findUser(users []user, name string) (v *user, err error) {
for _, u := range users {
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
- 返回值: 函数
findUser返回两个值:一个是找到的用户指针,另一个是错误信息。 - 返回错误: 如果找到用户,则返回用户指针和
nil;如果未找到用户,则返回nil和错误信息。
错误处理
在调用返回错误的函数时,可以使用 if-else 语句来处理错误。
func main() {
u, err := findUser([]user{{"wang", "1024"}}, "wang")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) // wang
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
}
- 处理错误: 调用
findUser函数后,检查返回的错误。如果有错误,则打印错误信息并返回;如果没有错误,则继续处理返回的结果。
总结
- 错误类型: Golang 使用内置的
error接口来表示错误。 - 函数返回错误: 在函数返回值类型列表中添加
error类型,表示该函数可能会返回错误。 - 错误处理: 使用
if-else语句来处理函数返回的错误,清晰地知道哪个函数返回了错误,并进行相应的处理。