golang面试题2022

2 篇文章 0 订阅

切片相关

1.nil切片和空切片区别

指向引用数组的地址不同,

nil切片指向引用数组为0(无实际意义)

空切片的引用数组指针地址是有的,且固定为一个值

golang的数组和切片相关的问题

golang数组作为参数传递默认情况是用的值传递,想要修改的情况下应该用引用传递。所以值传递情况下对值的修改无效

package main

import "fmt"

func main() {
	arr := [8]int{}
	for i := 0; i < 8; i++ {
		arr[i] = i
	}

	fmt.Println(arr)
    exchange(arr)
	fmt.Println(arr)
	exchangeByAddress(&arr)
	fmt.Println(arr)
    slice := []int{1,2,3,4,5}
    fmt.Println(slice)
    exchangeSlice(slice)
	fmt.Println(arr)
}
func exchange(arr [8]int) {
	for k, v := range arr {
		arr[k] = v * 2
	}
}
func exchangeByAddress(arr *[8]int) {
	for k, v := range *arr {
		arr[k] = v * 2
	}
}
func exchangeSlice(slice []int) {
	for k, v := range slice {
		slice[k] = v * 2
	}
}

           切片作为参数传递默认情况下用的是引用传递,所以不能再次传递切片指针。上面代码可以查看一下

语法糖相关

接收者方法

在 Go 中,对于自定义类型 T,为它定义方法时,其接收者可以是类型 T 本身,也可能是 T 类型的指针 *T。

type Instance struct{}

func (ins *Instance) Foo() string {
 return ""
}

在上例中,我们定义了 Instance 的 Foo 方法时,其接收者是一个指针类型(*Instance)。

func main() {
 var _ = Instance{}.Foo() // 编译错误:cannot call pointer method on Instance{}
}

 因此,如果我们用 Instance 类型本身 Instance{} 值去调用 Foo 方法,将会得到以上错误

type Instance struct{}

func (ins Instance) Foo() string {
 return ""
}

func main() {
 var _ = Instance{}.Foo() // 编译通过
}

此时,如果我们将 Foo 方法的接收者改为 Instance 类型,就没有问题。

这说明,定义类型 T 的函数方法时,其接收者类型决定了之后什么样的类型对象能去调用该函数方法。但,实际上真的是这样吗?

type Instance struct{}

func (ins *Instance) String() string {
 return ""
}

func main() {
 var ins Instance
 _ = ins.String()
}

实际上,即使是我们在实现 Foo 方法时的接收者是指针类型,上面 ins 调用的使用依然没有问题。

Ins 值属于 Instance 类型,而非 *Instance,却能调用 Foo 方法,这是为什么呢?这其实就是 Go 编译器提供的语法糖!

当一个变量可变时,我们对类型 T 的变量直接调用 *T 方法是合法的,因为 Go 编译器隐式地获取了它的地址。变量可变意味着变量可寻址,因此,上文提到的 Instance{}.Foo() 会得到编译错误,就在于 Instance{} 值不能寻址。

defer 在 return 之后执行

package main

import (
 "fmt"
)

func hello(i *int) int {
 defer func() {
  *i = 19
 }()
 return *i
}

func main() {
 i := 10
 j := hello(&i)
 fmt.Println(i, j)
}

上面的输出结果是19,10

知识点1:指针传递的方式,值得改变影响函数外部。知识点2:defer之后之后执行的是修改i的值,但是对返回值不受影响。下面derfer修改的值是函数返回值的话,就影响了返回值的结果

func hello(i *int) (j int) {
  defer func() {
    j = 19
  }()
  return *i
}

sync.Map 中定义的泛类型定义

package main

import (
 "fmt"
 "sync"
)

func main() {
 var m sync.Map
 m.Store("address", map[string]string{"province": "江苏", "city": "南京"})
 v, _ := m.Load("address")
 fmt.Println(v["province"])
}

这道题目的关键是 sync.Map 相关的定义(主要看本题使用了的 Store 和 Load):

func (m *Map) Load(key interface{}) (value interface{}, ok bool)
func (m *Map) Store(key, value interface{})

看到了没?接收的 key 和 value 都是 interface{}(返回的 value 也是 interface{}),所以,通过 Load 获取 key 对应的 value 是一个 interface{}。fmt.Println(v["province"]) 这句相当于把 interface{} 当成 map 了,肯定报错,必须进行类型断言。你答对了吗?

面向对象的理解->引入接口的相关的知识点

golang 属于面向对象的风格,但是也有面向过程的一些特征。面向对象最主要的是封装,继承,多态。golang通过隐式继承,语法糖表现方式是infterface 接口和结构体struct,struct可以不停嵌入新的结构体

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值