go面试笔记

go面试笔记,第1张

    • IO模型
    • PCB
    • socket
    • gorountine调度
    • defer
      • 1先进后出
      • 2遇到panic ,先defer后panic
      • 3 defer语句包含函数的 先执行函数 再defer
      • 4 defer和return
    • select
    • context
    • 继承/方法
    • go fun( )闭包
      • 1.变量值未被修改:
      • 2变量值被修改
    • make和new初始化
    • iota
    • 结构体比较
    • append多个元素
    • 短变量声明
    • 常量
    • 自定义类型和别名
    • 结构体和结构体别名
    • 变量作用域

IO模型

PCB

socket




gorountine调度



defer 1先进后出
func Defer(){
	for i:=0;i<5;i++{
		fmt.Println(i)
	}
}
defer : 4
defer : 3
defer : 2
defer : 1
defer : 0

先进后出

2遇到panic ,先defer后panic
func defer_call() {
	defer func() { fmt.Println("打印前") }()
	defer func() { fmt.Println("打印中") }()
	defer func() { fmt.Println("打印后") }()

	panic("触发异常")
}
打印后
打印中
打印前
panic: 触发异常
3 defer语句包含函数的 先执行函数 再defer

4 defer和return
func main() {

	fmt.Println("user1",DeferFunc1(1))
	fmt.Println("user2",DeferFunc2(1))
	fmt.Println("user3",DeferFunc3(1))
}

func DeferFunc1(i int) (t int) {
	t = i
	defer func() {
		fmt.Println("d1",t)
		t += 3
	}()
	fmt.Println("r1",t)
	return t
}

func DeferFunc2(i int) int {
	t := i
	defer func() {
		fmt.Println("d2",t)
		t += 3
	}()
	fmt.Println("r2",t)

	return t
}

func DeferFunc3(i int) (t int) {
	defer func() {
		fmt.Println("d3",t)
		t += i
	}()
	fmt.Println("r3",t)

	return 2
}

执行顺序

r1 1
d1 1
user1 4
r2 1
d2 1
user2 1
r3 0
d3 2
user3 3
select

配合case用于channel

1.Go的select语句是一种仅能用于channl发送和接收消息的专用语句,此语句运行期间是阻塞的;当select中没有case语句的时候,会阻塞当前groutine。

2.select是Golang在语言层面提供的I/O多路复用的机制,其专门用来检测多个channel是否准备完毕:可读或可写。

3.select语句中除default外,每个case *** 作一个channel,要么读要么写

4.select语句中除default外,各case执行顺序是随机的

5.select语句中如果没有default语句,则会阻塞等待任一case

6.select语句中读 *** 作要判断是否成功读取,关闭的channel也可以读取 作者:地鼠文档 https://www.bilibili.com/read/cv10128860/ 出处:bilibili

context

Context 的结构非常简单,它是一个接口。

Context 提供跨越API的截止时间获取,取消信号,以及请求范围值的功能。//
它的这些方案在多个 goroutine 中使用是安全的

  type Context interface {
   // 如果设置了截止时间,这个方法ok会是true,并返回设置的截止时间 
   Deadline() (deadline time.Time, ok bool)
    // 如果 Context 超时或者主动取消返回一个关闭的channel,如果返回的是nil,表示这个 
    // context 永远不会关闭,比如:Background() 
    Done() <-chan struct{} 
    // 返回发生的错误 
    Err() error
     // 它的作用就是传值
     Value(key interface{}) interface{}
     }
 写到这里,我们打住想一想,如果你来实现这样一个能力的 package,你抽象的接口是否也是具备这样四个能力?

获取截止时间
获取信号
获取信号产生的对应错误信息
传值专用

继承/方法

go fun( )闭包

闭包捕获对外部变量是通过引用的方式实现的;会随着外部变量的改变而修改。为避免此问题可:
通过参数方式传入外部变量;
定义局部变量的方式;

func delayPrint() {
    // 通过参数方式保证每个变量值是不同的;
	for i := 0; i < 3; i++ {
		go func(i int) {
			time.Sleep(time.Second * 1)
			fmt.Println("By param: ", i)
		}(i)
	}
	time.Sleep(time.Second * 4)
	
    // 直接引用外部变量,会发现所有调用最终都捕获了同一个变量值
	for i := 0; i < 3; i++ {
		go func() {
			time.Sleep(time.Second * 1)
			fmt.Println("By clouser: ", i)
		}()
	}
	time.Sleep(time.Second * 4)

    // 通过引入局部变量方式,保证捕获的变量是不同的
	for i := 0; i < 3; i++ {
		tmp := i
		go func() {
			time.Sleep(time.Second * 1)
			fmt.Println("By tmp: ", tmp)
		}()
	}
	time.Sleep(time.Second * 4)
}

// By param:  2
// By param:  0
// By param:  1
// By clouser:  3
// By clouser:  3
// By clouser:  3
// By tmp:  0
// By tmp:  2
// By tmp:  1
————————————————

1.变量值未被修改:

捕获变量c对应两个地址
闭包函数对应一个地址

f 1 在 栈 上 存 一 个 地 址 a d d r 2 , a d d r 2 存 储 两 个 值 , 捕 获 变 量 c 和 函 数 入 口 地 址 a d d r 1 \color{#A0A}{f1在栈上存一个地址addr2 ,addr2存储两个值 , 捕获变量c和函数入口地址addr1} f1addr2addr2caddr1
f 2 在 栈 上 存 一 个 地 址 a d d r 3 , a d d r 3 存 储 两 个 值 , 捕 获 变 量 c 和 函 数 入 口 地 址 a d d r 1 \color{#A0A}{f2在栈上存一个地址addr3 , addr3存储两个值 , 捕获变量c和函数入口地址addr1} f2addr3addr3caddr1

2变量值被修改



1两次循环闭包的捕获变量存储的都是地址,create执行完i的值是2,这个地址写入了返回值
2返回值拷贝给fs的时候,这个捕获变量i地址指向的值就是2
3调用fs[i]的时候,addr0,addr1一次写入寄存器,两个闭包捕获变量地址指向同一个位置,值是2

make和new初始化


new:

iota


1 iota配合const使用
2 行数的索引,从0开始,在第几行iota就是几
3 常亮没有赋值的,上一行是iota,+1;上一行是int,=上一行的值


定义在同一行就是同一个index

结构体比较
	sn1 := struct {
		age  int
		name string
	}{age: 11, name: "qq"}
	sn2 := struct {
		age  int
		name string
	}{age: 11, name: "qq"}

	if sn1 == sn2 {
		fmt.Println("sn1 == sn2")
	}

结构体只有在属性相同 类型相同 顺序相同才可以==,否则panuc

append多个元素

短变量声明
var(
    size =1024
    max_size = size*2
)
func main()  {
	size2:=65536
    fmt.Println(size,max_size,size2)
}

只能在func内部,全局变量不能用:=

常量


常量不能取地址

自定义类型和别名
//一、类型别名  用=

type byte=uint8
type rune=int32

//二、区别类型别名和类型定义

// 自定义类型myInt,基本类型是int
type myInt int
//将 int 类型取一个别名intAlias
type intAlias = int
func main() {
 var a myInt  //声明 a变量为自定义 myInt 类型
 fmt.Printf("a Type: %T, value: %d\n", a, a)  // 输出 a 的类型和默认值
 var b intAlias  //声明 b变量为 intAlias 类型
 fmt.Printf("b Type: %T, value: %d\n", b, b) // 输出 b 的类型和默认值
}
a Type: main.myInt, value: 0

b Type: int, value: 0

//从上面的结果我们可以看出:

//a 的类型是  main.myInt,表示main 包下定义的myInt 类型

//b  的类型是 int 。intAlias 类型只会在代码中存在,编译完成时,不会有 intAlias 类型``

```go

结构体和结构体别名

变量作用域

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/758082.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-01
下一篇2022-05-01

发表评论

登录后才能评论

评论列表(0条)

    保存