- 什么是 Go 切片? 答:Go 切片是一种动态数组,它能够自动扩容,这意味着无需预先分配数组长度。切片在使用前不需要定义长度,底层会自动根据需要扩容。
- 什么是 Goroutine? 答:Goroutine 是 Go 语言的轻量级线程,它可以在不同的执行路径上运行,通过使用 Go runtime 管理,可以实现并发执行。同时,Goroutine 的开销较小,Go 语言可以支持大量 Goroutine 的同时执行。
- 什么是 Go 接口? 答:Go 接口是指定了一组方法签名的抽象类型。实现了这个方法签名的类型就可以实现该接口。接口实现了 Go 语言中的多态机制,它比继承更加灵活。
- 什么是 Go defer? 答:defer 是 Go 语言提供的一种机制,用来在函数退出前执行释放资源等善后工作。defer 主要用于在函数返回前释放资源或呈现内容。
- 什么是 Go 并发安全?
答:Go 并发安全可以确保在多协程并发时,共享的数据结构不会出现竞态条件。 互斥锁(Mutex) 和 读写锁(RLock) 是 Go 语言中最常用的并发安全解决方案。
- 如何自定义 HTTP 客户端超时?
答:可以使用 Context 来跟踪请求并设置超时,通过创建一个带时间的上下文(Context)和使用 Timeout 方法即可。
-
Go 中变量的作用域有哪些? 答:Go 中的变量作用域可以分为以下几种:
- 函数内部声明的变量作用域为函数内部。
- 外部包中的变量是全局变量,其他包可以使用。
- 通常结构体与接口定义的字段作用于整个包。
-
如何封装 Go 结构体? 答:结构体是一种可以定义各种类型的数据结构,并与函数和方法关联的新类型。Go 提供了私有和公有的访问控制权限,可以使用小写字母定义私有成员,大写字母定义公有成员,用于封装和保护数据。
-
如何防止 Go 的资源泄漏? 答:编写 Go 代码时,开发人员可以动态分配内存和创建 Goroutine 以便高效、可扩展。但是这也可能会导致资源泄漏。主要是通过关闭文件、释放数据库连接和避免创建出现无限循环等。
-
Go 如何识别 nil 值? 答:nil 值在 Go 中表示指针或接口的底层类型为 nil。可以通过类型断言或使用 value == nil 来判断指针或接口是否为 nil。
代码题
-
请解释下面一段代码的输出:
Copy code package main import "fmt" func main() { a := make([]int, 5) b := make([]int, 5, 10) fmt.Println(a, len(a), cap(a)) fmt.Println(b, len(b), cap(b)) }
答:该代码将创建两个长度为5的整型切片。变量 a 没有使用第三个参数,因此,底层数组的大小为5。变量b 使用了第三个参数10,因此底层数组的大小为10。输出结果为:
Copy code
[0 0 0 0 0] 5 5
[0 0 0 0 0] 5 10
-
请解释下面一段代码:
Copy code package main import "fmt" func main() { ch := make(chan int, 1) ch <- 1 fmt.Println(<-ch) }
答:该代码将创建了一个缓冲区大小为1的整型channel。然后向channel发送一个1,最后从该channel接收数据并打印。因为channel是带缓冲的,可以安全的发送和接收数据。
-
请解释下面一段代码的输出:
Copy code package main import "fmt" func main() { var a []int fmt.Println(a == nil) a2 := []int{} fmt.Println(a2 == nil) }
答:该代码将创建了两个整型切片,第一个切片 a 没有分配内存因此值为 nil,第二个切片 a2 是个空切片,因此不是 nil。
输出结果为:
Copy code
true
false
-
请解释下面一段代码:
Copy code package main import ( "fmt" "sync" ) var wg sync.WaitGroup func main() { for i := 1; i <= 5; i++ { wg.Add(1) go processData(i) } wg.Wait() } func processData(id int) { defer wg.Done() fmt.Println("Processing started for ", id) }
答:该代码将并发处理5个不同的进程。我们使用 WaitGroup 来等待所有进程完成。每个进程在处理之前,调用 Add() 增加 WaitGroup 的计数器,处理完成之后,调用 Done() 函数来减少计数器。
输出结果为:
Copy code
Processing started for 1
Processing started for 2
Processing started for 3
Processing started for 4
Processing started for 5
-
请解释下面一段代码:
Copy code package main import ( "fmt" ) func main() { a := [3][2]string{ {"apple", "banana"}, {"pear", "plum"}, {"peach", "kiwi"}, } for i, v := range a { for j, val := range v { fmt.Printf("[%d][%d] = %s\n", i, j, val) } } }
答:该代码创建了一个三行两列的字符串数组。然后使用嵌套 for 循环遍历该数组,并将数组元素的值打印到控制台。
输出结果为:
Copy code
[0][0] = apple
[0][1] = banana
[1][0] = pear
[1][1] = plum
[2][0] = peach
[2][1] = kiwi
-
请解释下面一段代码:
Copy code package main import ( "fmt" "os" ) func main() { file, err := os.Open("file.txt") if err != nil { fmt.Println(err) return } defer file.Close() // Use the file variable. }
答:该代码首先尝试打开文件 file.txt。如果打开文件不成功,它将打印错误并返回;否则,它会使用 defer 语句来确保在函数退出前,关闭文件。
-
请解释下面一段代码:
Copy code package main import ( "fmt" "time" ) func main() { fmt.Println("Started") for i := 1; i <= 5; i++ { go process(i) } time.Sleep(time.Second * 2) } func process(i int) { fmt.Println("Processing ", i) time.Sleep(time.Second) }
答:该代码将并发运行 5 个群体。main() 函数打印 "Started" ,然后启动 5 个 Goroutine 进程,这些进程将 process() 函数作为参数,并传递一个整数参数。每个 process(i) 函数打印一个正在执行的消息,并休眠一秒钟。然后,main() 函数休眠 2 秒钟,这样所有的 Goroutine 进程都将有足够的时间完成它们的工作。
输出结果为:
Copy code
Started
Processing 1
Processing 4
Processing 2
Processing 3
Processing 5
-
请解释下面一段代码:
Copy code package main import "fmt" func main() { a := [3]int{1, 2, 3} for _, v := range a { fmt.Println(v) } }
答:该代码将创建一个整型数组,然后使用 range 表达式中的 _ 替换了循环变量索引 i。因此,可以使用变量 v 访问数组中的元素。使用循环将每个数组值打印到控制台。
输出结果为:
Copy code
1
2
3
-
请解释下面一段代码的输出:
Copy code package main import "fmt" func main() { var x float64 = 15.5 fmt.Printf("x is of type %T\n", x) var y = "Hello, World!" fmt.Printf("y is of type %T\n", y) }
答:该代码将声明变量 x 为 float64 类型并赋值,然后将该变量的类型用格式符 %T 打印到控制台。接下来,变量 y 赋值为一个字符串,并将该变量的类型使用格式符 %T 打印到控制台。
输出结果为:
Copy code
x is of type float64
y is of type string
-
请解释下面一段代码:
Copy code package main import ( "fmt" "net/http" ) func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello, World!") } func main() { http.HandleFunc("/", hello) http.ListenAndServe(":80", nil) }
答:该代码使用 Go 的 http 包创建了一个简单的 Web 服务器。我们定义了一个名为 hello() 的函数,它接受 http.ResponseWriter 和 *http.Request 两个参数,且在请求时输出 "Hello, World!" 到客户端。 在 main() 函数中,通过调用 http.HandleFunc() 函数来处理请求,向默认路由 / 的使用者响应。
Copy code
最后,我们通过 `http.ListenAndServe()` 函数来监听特定端口的 HTTP 请求。在本例中,我们监听 80 端口,也就是 Web 服务器默认的 HTTP 端口。