面试题答案
一键面试变量作用域对生命周期的影响
在Go语言中,变量的作用域决定了该变量在程序中可被访问的范围,同时也对其生命周期产生影响。当变量离开了其作用域,它就会被释放,生命周期结束。
局部变量特点
- 作用域:局部变量在定义它的代码块内有效,例如函数内部的代码块,或
for
、if
语句块等。 - 生命周期:局部变量的生命周期从声明开始,到所在代码块结束时结束。一旦代码块执行完毕,局部变量占用的内存可能会被回收(取决于是否有其他引用)。
示例:
package main
import "fmt"
func localVarExample() {
// 局部变量a的作用域开始
a := 10
fmt.Println(a)
} // 局部变量a的作用域结束,a可能被回收
func main() {
localVarExample()
}
全局变量特点
- 作用域:全局变量在整个包内都可访问,如果导出(首字母大写),还能在其他包中访问。
- 生命周期:全局变量的生命周期从程序启动开始,到程序结束才结束。
示例:
package main
import "fmt"
// 全局变量b
var b int = 20
func globalVarExample() {
fmt.Println(b)
}
func main() {
globalVarExample()
}
并发场景下变量生命周期问题及解决方案
- 问题:在并发场景下,多个goroutine可能同时访问和修改同一个变量,这可能导致数据竞争问题。例如,一个goroutine可能在另一个goroutine还在使用某个变量时就释放了它,或者多个goroutine同时修改同一个变量导致结果不可预测。
- 解决方案:
- 互斥锁(Mutex):使用
sync.Mutex
来保护共享变量,确保同一时间只有一个goroutine能访问和修改变量。
package main import ( "fmt" "sync" ) var ( counter int mu sync.Mutex ) func increment(wg *sync.WaitGroup) { defer wg.Done() mu.Lock() counter++ mu.Unlock() } func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go increment(&wg) } wg.Wait() fmt.Println("Final counter:", counter) }
- 读写锁(RWMutex):当读操作远多于写操作时,使用
sync.RWMutex
可以提高性能。允许多个goroutine同时读,但写操作需要独占。 - 通道(Channel):通过通道在goroutine之间传递数据,避免共享变量,从而减少数据竞争问题。
package main import ( "fmt" ) func sendData(ch chan int) { for i := 0; i < 5; i++ { ch <- i } close(ch) } func main() { ch := make(chan int) go sendData(ch) for val := range ch { fmt.Println(val) } }
- 互斥锁(Mutex):使用