面试题笔试题学习日记——golang(8.03)

下面的代码输出什么?

func calc(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret 
}

func main() {
	a := 1
	b := 2
	defer calc("1", a, calc("10", a, b)) a = 0
	defer calc("2", a, calc("20", a, b)) b = 1
}

考点:defer执行顺序
解答:
这道题类似第一题,需要注意到defer执行顺序和值传递index:1肯定是最后执行的,但是index:1的第三个参数是一个函数,所以最先被调用
calc(“10”, 1, 2) = => 10, 1, 2, 3
执行到index:2时,与之前一样,需要先调用calc(“20”, 0, 2) = => 20, 0, 2, 2
执行到b = 1时候开始调用,index:2 = => calc(“2”, 0, 2) = => 2, 0, 2, 2
最后执行index:1 = => calc(“1”, 1, 3) = => 1, 1, 3, 4

10 1 2 3
20 0 2 2
2 0 2 2
1 1 3 4
请写出以下输入内容
func main() {
	s := make([]int, 5)
	s = append(s, 1, 2, 3)
	fmt.Println(s)
}

考点:make默认值和append
解答:
make初始化是有默认值的,此处默认值为0

[0 0 0 0 0 1 2 3]
下面的代码有什么问题
type UserAges struct {
	ages map[string]int
	sync.Mutex
}

func (ua *UserAges) Add(name string, age int) {
	ua.Lock()
	defer ua.Unlock()
	ua.ages[name] = age
}

func (ua *UserAges) Get(name string) int {
	if age, ok := ua.ages[name];ok {
		return age
	}
	return -1
}

考点:map线程安全
解答:
可能会出现fatel error: concurrent mapreadandmapwrite.
修改一下看看效果

func (ua *UserAges) Get(name string) int {
	ua.Lock()
	defer ua.Unlock()
	if age, ok := ua.ages[name];ok {
		return age
	}
	return -1
}
下面的迭代会有什么问题?
func (set *threadSafeSet) Iter() <-chan interface{} {
	ch := make(chan interface{})
	go func() {
		set.RLock()
		for elem := range set.s {
			ch <- elem
		}
		close(ch)
		set.RUnlock()
	}()
	return ch
}

考点:chan缓存池
解答:
看到这道题目,我也在猜想出题者的意图在哪里。chan?sync.RWMutex?go?chan缓存池?迭代?所以只能再读一次题目,就从迭代入手看看,既然是迭代就会要求ste.s全部可以遍历一次。但是chan是为缓存的,那就代表写入一次就会阻塞。我们把代码恢复为可以运行的方式,看看效果

package main

import (
	"sync"
	"fmt"
)

type threadSafeSet struct {
	sync.RWMutex
	s []interface{}
}

func (set *threadSafeSet) Iter() <-chan interface{} {
	// ch := make(chan interface{})
	ch := make(chan interface{}, len(set.s))
	go func() {
		set.RLock()
		for elem, value := range set.s {
			ch <- elem
			fmt.Println("Iter:", elem, value)
		}
		close(ch)
		set.RUnlock()
	}()
	return ch
}

func main() {
	th := threadSafeSet{
		s:[]interface{}{"1", "2"},
	}
	v := <-th.Iter()
	fmt.Sprintf("%s%v", "ch", v)
}
以下代码能编译过去吗?为什么?
package main

import "fmt"

type People interface {
	Speak(string) string
}

type Student struct {}

func (stu *Student) Speak(think stirng) (talk string) {
	if think == "bitch" {
		taik = "you are a good boy"
	} else {
		talk = "hi"
	}
	return
}

func main() {
	var peo People = Student{}
	think := "bitch"
	fmt.Println(peo.Speak(think))
}

考点:golang的方法集
解答:
编译不通过!做错了!?说明你对golang的方法集还有一些疑问。一句话:golang的方法集仅仅影响接口实现和方法表达式转化,与通过实例或者指针调用方法无关。

以下代码打印出来什么内容,说出为什么
package main

import "fmt"

type People interface {
	Show()
}

type Student struct {}

func (stu *Student) Show() {
}

func live() People {
	var stu *Student
	return stu
}

func main() {
	if live() == nil {
		fmt.Println("AAAAAAA")
	} else {
		fmt.Println("BBBBBBB")
	}
}

解答:interface内部结构
解答:
很经典的题!这个考点是很多人忽略的interface内部结构。go中的接口分为两种,一种是空接口,类似这样的:var in interface{},另一种如题目的:type People interface {Show()}
他们的地层结构如下

// 空接口
type eface struct {
	_type *_type  //类型信息
	data unsafe.Pointer  //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)
}

// 带有方法的接口
type iface struct {
	tab *itab  //存储type信息还有结构实现方法的集合
	data unsafe.Pointer  //指向数据的指针(go语言中特殊的指针类型unsafe.Pointer类似于c语言中的void*)
}

type _type struct {
	size		uintptr  //类型大小
	ptrdata 	uintptr  //前缀持有所有指针的内存大小
	hash		uint32   //数据hash值
	tflag		tflag
	align		uint8	 //对齐
	fieldalign  unit8	 //嵌入结构体时的对齐
	kind		uint8	 //kind 有些枚举值kind等于0是无效的
	alg			*typeAlg //函数指针数组,类型实现的所有方法
	gcdata		*byte
	str			nameOff
	ptrToThis	typeOff
}

type itab struct {
	inter		*interfacetype	//接口类型
	_type		*_type
	link		*itab
	bad			int32
	inhash		int32
	fun			[1]uintptr		//可变大小方法集合
}

可以看出iface比eface中间多了一层itab结构。itab存储_type信息和[]fun方法集,从上面的结构我们就可得出,因为data指向了nil并不代表interface是nil,所以返回值并不为空,这里的fun(方法集)定义了接口的接收规则,在编译过程中需要验证是否实现接口
结果:BBBBBBB

猜你喜欢

转载自blog.csdn.net/qq_37109456/article/details/107770815
今日推荐