Golang】面试总结

一、go语言基础

(1)一个包怎么调用另一包的函数,go语言中公有性和私有性怎么表达?

        函数大写表示公有,小写表示私有

(2)简单的介绍一下闭包使用场景,优缺点?

        首先闭包的特点是当闭包函数引用外部变量的时候,会把这个变量放在堆中,所以在内部函数引用外部函数的变量时,值不会被释放 

        
package main

import "fmt"

func externalFunc(count int) func() int{

    return func() int {
        count++
        return count
    }
}

func main()  {

    // 这时候的external是个函数,externalFunc函数返回了个匿名函数
    external := externalFunc(1)  // 这时候的count == 1
    fmt.Println(external()) //输出2
    fmt.Println(external()) //输出3
    fmt.Println(external()) //输出4
}

用法1.函数计数器

// 函数计数器
func counter(f func()) func() int {  
	n := 0
	return func() int {
		f()
		n += 1
		return n
	}
}

// 测试的调用函数
func foo() {
	fmt.Println("call foo")
}

func main() {
	cnt := counter(foo)
	cnt()
	cnt()
	cnt()
	fmt.Println(cnt())
}
/*
输出结果:
call foo
call foo
call foo
call foo
4
*/
2)装饰器和中间件,即函数作为参数传递

func wrapping(f func() string) {
	fmt.Println("do my work...")
	fmt.Println("wrapping function: ", f())
	fmt.Println("my work finished !")
}

func sayHello() string {
	return "Hello !"
}

func sayByeBye() string {
	return "Bye Bye !"
}

func main() {
	wrapping(sayHello)
	wrapping(sayByeBye)
}
/*
输出:
do my work...
wrapping function:  Hello !
my work finished !
do my work...
wrapping function:  Bye Bye !
my work finished !
*/

(3)map和array make的使用区别?

        go语言中new和make是内置函数,主要用来创建分配类型内存。

        new(T)创建一个没有任何数据的类型为T的实例,并返回该实例的 指针;

       make(T,args)   只能创建slice,map,channel,并返回一个有初始值args(非零)的T类型的实例,非指针。

        二者都是内存的分配(堆上),但是make只用于slice、map、channel的初始化,而new用于类型的内存分配,并且内存内置为0.

        make返回的还是这三个引用类型本身;而new返回的是指向类型的指针。


        slice和array接近,不过更加的灵活,可以在新的元素加入的时候增加长度。slice总是指向底层的一个array。slice是一个指向array的指针,这是其与array不同的地方;slice是引用类型,这意味着当赋值某个slice到另外一个变量,两个引用会指向同一个array。 例如,如果一个函数需要一个slice参数,在其内对slice元素的修改也会体现在函数调用者中,这和传递底层的array指针类似。
    

        append: 向slice追加零值或者其他的x值,并且返回追加后的新的slice。如果原来的slice没有足够的容量,那么append会分配一个足够大的,新的slice来存放原来的slice和后面追加的值。因此返回的slice可能和原来的不是指向同一个array


        Slice 所允许申请的最大容量大小,与当前值类型和当前平台位数有直接关系

        slice扩容机制

                1.如果切片的容量小于1024个元素,那么扩容的时候slice的cap就翻番,乘以2;一旦元素个数超过1024个元素,增长因子就变成1.25,即每次增加原来容量的四分之一。

                2.如果扩容之后,还没有触及原数组的容量,那么,切片中的指针指向的位置,就还是原数组,如果扩容之后,超过了原数组的容量,那么,Go就会开辟一块新的内存,把原来的值拷贝过来,这种情况丝毫不会影响到原数组。

        make创建

        make([]T, length, capacity) 
    slice1 := make([]T, length)

    length 表示slice中已经使用的数据长度

    capacity 表示slice中指针执行的数组容量,如果缺省capacity 和length大小相等

    Go language slice detailed explanation (combined with source code)

(4)defer的工作模式

        go 的 defer 语句是用来延迟执行函数的,而且延迟发生在调用函数 return 之后,同时defer的执行顺序和栈类似,先进后出

(5)匿名函数的使用(难点)

        常用的感觉就是闭包和go func协程了,再说吧。。。。。

二、面向对象和并发

(1)go语言如何表现继承

        go中没有extends关键字,所以没有原生级别的继承。go本质上是使用interface实现的,是使用组合来实现继承,用组合来代替继承。

        在go的结构体struct,通过匿名成员的方式实现继承,比如,Student继承了Men

    

type Men struct {
    name string
    age int
}
 
type Student struct {
    Men
    score int
}

对于接口interface,通过直接引入另一接口的方式实现继承,比如,ReadWriter继承了Reader和Writer

type Reader interface {
}
 
type Writer interface {
}
 
type ReadWriter interface {
	Reader
	Writer
}

(2)接口的优点,使用场景。

      实现代码解耦

(3)并发通信采用什么消息机制。

    goroutine  + channel数据共享

欢迎留言