概述
- map的原理
- 字典[map]:
初始化: var amap map[string]string, 如果需要赋值,需要先make 一下
testMap := make(map[string]string)
Go中的字典是引用类型,但Golang中是没有引用传递的,均为值传递。这意味着传递的是数据的拷贝,所以map 也存在线程安全的问题
底层结构是hmap,hmap 的结构体里有一个buckets,他是一个指针,指向了一个bucket的结构体,bucket可以看错一个链表,bucket 里存放着k&&v 的数组,以及指向下一个bucket的指针。
所以当hmap收到了key,会进行hash运算,然后基于运算结果找到对应的bucket里的数组,然后找到对应的Key
- make和new的区别
- new:用来初始化一个对象,并且返回该对象的首地址.其自身是一个指针.可用于初始化任何类型
- make:返回一个初始化的实例,返回的是一个实例,而不是指针,其只能用来初始化:slice,map和channel三种类型
- go的GC 机制
- 标记-清除模式: 从根变量开始遍历所有引用的对象,引用的对象标记为"被引用",没有被标记的进行回收。
- defer的执行顺序
多个defer 执行顺序类似堆栈,后进先出,defer、return、返回值三者的执行逻辑应该是:return最先执行,return负责将结果写入返回值中;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出。
如果函数的返回值是无名的(不带命名返回值),则go语言会在执行return的时候会执行一个类似创建一个临时变量作为保存return值的动作,而有名返回值的函数,由于返回值在函数定义的时候已经将该变量进行定义,在执行return的时候会先执行返回值保存操作,而后续的defer函数会改变这个返回值(虽然defer是在return之后执行的,但是由于使用的函数定义的变量,所以执行defer操作后对该变量的修改会影响到return的值
package main
import (
"fmt"
)
func haveReturnName() (a int) {
defer func() {
a++
}()
return a
}
func haveNoReturnName() (int) {
var b int
defer func() {
b++
}()
return b
}
func main() {
fmt.Println(haveReturnName())
fmt.Println(haveNoReturnName())
}
- recover && panic
go没有 try, expect,finnally 之类的异常捕捉方法,通过defer 判断是否捕捉到recover,如果没有则返回nil,如果recover捕获到panic,则处理。
package main
import "fmt"
func prTest() {
defer func() {
if r := recover(); r != nil {
fmt.Printf("panic recover! %v",r)
}
}()
for i := 0; i < 5; i++ {
if i == 3 {
panic(fmt.Sprintf("%v",i))
}
fmt.Println(i)
}
}
func main() {
prTest()
}
- golang 如何处理大文件?
- 切片(数据流),适合二进制文件,没有换行符的,非常大的http返回
package main
import (
"os"
"fmt"
)
func readBigFile(fileName string) {
f, err := os.Open(fileName)
if err != nil {
fmt.Println("can't opened this file")
panic(err.Error())
}
defer f.Close()
s := make([]byte, 1024)
for {
switch nr, _ := f.Read(s[:]); true{
case nr > 0:
fmt.Println(nr)
case nr <= 0: //EOF
return
}
}
}
func main() {
readBigFile("loutong.go")
}
- 逐行读取
package main
import (
"bufio"
"fmt"
"os"
"io"
)
func readBigFile(fileName string) {
f, err := os.Open(fileName)
defer f.Close()
if err != nil {
panic(err.Error())
}
buf := bufio.NewReader(f)
for {
c, _, err := buf.ReadLine()
fmt.Printf("%sn",c)
if err == io.EOF {
return
}
if err != nil && err != io.EOF {
fmt.Printf("读取错误")
return
}
}
}
func main() {
readBigFile("loutong.go")
}
- go的context作用
- 批量协程的关闭
- 协程的超时处理
package main
import (
"context"
"time"
"fmt"
)
func ctxCancelThing() {
ctx, cancel := context.WithCancel(context.Background())
go doSomething(ctx)
time.Sleep(10 * time.Second)
cancel()
}
func ctxTimeoutThing() {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5 * time.Second))
go doSomething(ctx)
time.Sleep(10 * time.Second)
cancel()
}
func doSomething(ctx context.Context) {
for {
time.Sleep(1 * time.Second)
select {
case <-ctx.Done():
fmt.Printf("done")
return
default:
fmt.Printf("work")
}
}
}
func main() {
ctxCancelThing()
ctxTimeoutThing()
}
-
谈谈go的协程泄露
一个原则,在不知道如何关闭一个协程的情况下,永远不要启动一个goroutine。 -
select 和 switch的区别
select 不带判断条件,主要是用于判断IO操作的,确切的说,应该是一个面向channel的IO操作 -
go语言中布尔类型的缺省值是什么?
False
个人公众号, 分享一些日常开发,运维工作中的日常以及一些学习感悟,欢迎大家互相学习,交流
最后
以上就是文静野狼为你收集整理的golang 常见面试基础(2)的全部内容,希望文章能够帮你解决golang 常见面试基础(2)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复