1.go语言中defer的变量快照在什么情况下会生效
1. 变量在 defer
被注册时的值被捕获
当 defer
被注册时,它会捕获变量在那一刻的值。如果变量是值类型(如基本类型、结构体等),defer
会捕获该值的副本;如果变量是指针类型,defer
会捕获指针本身,而不是指针指向的值。
示例 1:值类型变量
func main() {x := 5defer fmt.Println(x) // 捕获 x 的当前值 5x = 10fmt.Println("x is now", x) // 输出 x is now 10
} // defer 的 fmt.Println(x) 在这里执行,输出 5
- 在
defer
被注册时,x
的值是5
,defer
捕获了这个值。 - 后续对
x
的修改(x = 10
)不会影响defer
捕获的值。 - 最终,
defer
调用fmt.Println(x)
时输出的是5
,而不是10
。
示例 2:指针类型变量
func main() {x := 5p := &xdefer fmt.Println(*p) // 捕获指针 p,而不是 p 指向的值x = 10fmt.Println("x is now", x) // 输出 x is now 10
} // defer 的 fmt.Println(*p) 在这里执行,输出 10
- 在
defer
被注册时,捕获的是指针p
,而不是p
指向的值。 - 后续对
x
的修改(x = 10
)会改变p
指向的值。 - 最终,
defer
调用fmt.Println(*p)
时输出的是10
,而不是5
。
2. 闭包中的变量捕获
如果 defer
调用的是一个闭包(匿名函数),闭包会捕获变量的当前值。捕获的值取决于闭包的定义方式。
示例 3:闭包捕获值类型变量
func main() {x := 5defer func() {fmt.Println(x) // 捕获 x 的当前值 5}()x = 10fmt.Println("x is now", x) // 输出 x is now 10
} // defer 的闭包在这里执行,输出 5
- 闭包捕获了变量
x
在defer
被注册时的值5
。 - 后续对
x
的修改不会影响闭包捕获的值。 - 最终,闭包输出的是
5
,而不是10
。
示例 4:闭包捕获指针类型变量
func main() {x := 5p := &xdefer func() {fmt.Println(*p) // 捕获指针 p,而不是 p 指向的值}()x = 10fmt.Println("x is now", x) // 输出 x is now 10
} // defer 的闭包在这里执行,输出 10
- 闭包捕获的是指针
p
,而不是p
指向的值。 - 后续对
x
的修改会改变p
指向的值。 - 最终,闭包输出的是
10
,而不是5
。
总结
defer
的变量快照在以下情况下生效:
- 值类型变量:
defer
捕获变量在defer
被注册时的值的副本。后续对变量的修改不会影响defer
捕获的值。 - 指针类型变量:
defer
捕获指针本身,而不是指针指向的值。后续对指针指向的值的修改会影响defer
的输出。 - 闭包中的变量捕获:闭包会捕获变量在
defer
被注册时的值,捕获的值取决于变量的类型(值类型或指针类型)。
2.在 Go 语言中,通过指针变量 p 访问其成员变量 title 有以下几种方式
1. 直接通过指针访问成员变量
p := &b
fmt.Println(p.title)
p
是一个指向Book
的指针。- 通过
p.title
直接访问Book
的成员变量title
。 - 这种方式是直接通过指针访问成员变量,不需要显式解引用。
2. 先解引用指针,再访问成员变量
p := &b
fmt.Println((*p).title)
(*p)
表示对指针p
进行解引用,得到Book
类型的变量。- 然后通过
(*p).title
访问成员变量title
。 - 这种方式显式地展示了指针解引用的过程。
3. 使用方法访问成员变量
如果结构体中定义了方法,可以通过方法间接访问成员变量。例如:
func (b *Book) GetTitle() string {return b.title
}func main() {b := Book{title: "Go Programming"}p := &bfmt.Println(p.GetTitle()) // 通过方法访问成员变量
}
- 定义了一个方法
GetTitle
,它返回title
的值。 - 通过指针
p
调用GetTitle
方法,间接访问title
。
4. 使用指针解引用后赋值给一个新的变量
p := &b
b := *p
fmt.Println(b.title)
- 先通过
*p
解引用得到Book
类型的变量b
。 - 然后通过
b.title
访问成员变量。
5. 使用指针传递给函数并访问成员变量
func printTitle(book *Book) {fmt.Println(book.title)
}func main() {b := Book{title: "Go Programming"}p := &bprintTitle(p) // 通过函数访问成员变量
}
- 定义了一个函数
printTitle
,它接收一个指向Book
的指针。 - 将指针
p
传递给函数printTitle
,在函数内部通过指针访问成员变量title
。
总结
通过指针变量 p
访问其成员变量 title
的几种方式:
- 直接访问:
p.title
- 解引用后访问:
(*p).title
- 通过方法访问:
p.GetTitle()
- 解引用后赋值给新变量:
b := *p; b.title
- 传递指针给函数:
printTitle(p)
自学go语言笔记,希望我们可以一起学习!