网站首页 区块链学习

Golang】面试总结

发布时间:2021-3-1 8:58 Monday编辑:admin阅读(429)

    一、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数据共享