golang 20道基础语法相关面试题

1、介绍一下Golang的特点和优点?

答:Golang是一种由Google开发的开源编程语言,具有并发编程能力强、内存管理优秀、语法简洁、性能高效、代码可读性好、静态类型安全、跨平台支持等特点。同时还有如优点:

内存使用效率高:Golang的垃圾回收机制可以在运行时自动回收不再使用的内存,同时Golang的指针机制也可以减少不必要的内存拷贝,使得Golang的内存使用效率更高。

平台移植性好:Golang可以运行在不同的操作系统和硬件平台上,通过交叉编译可以很容易地将程序部署到不同的环境中。

标准库丰富:Golang的标准库提供了丰富的功能,包括网络编程、加密解密、文本处理、压缩解压、正则表达式等,可以满足大部分应用的需求。

代码风格一致:Golang强制采用一致的代码风格和命名规范,使得不同开发者之间可以更加容易地协作和交流。

开发效率高:Golang的语法简洁,代码可读性好,同时也提供了很多方便的工具和框架,可以提高开发效率和代码质量。

开源社区活跃:Golang是一个开源项目,拥有庞大的开源社区,社区成员可以共享代码、工具和经验,使得Golang的生态系统更加繁荣和稳定。

2、 什么是Go程序的基本语法?

一个Go程序通常以包声明开始,接着是导入语句,然后是主函数main)。

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

3、Go的基本数据类型有哪些?

Go语言的数据类型可以分为以下四种类型:

(1)基本类型:数字类型、布尔类型、字符串类型。

  • 数字类型:
    • 整数类型(intuint
    • 浮点数类型(float32float64
    • 复数类型(complex64complex128
  • 布尔类型(bool
  • 字符串类型(string、byte、rune

(2)聚合类型:数组和结构属于此类型

  • 数组
  • 结构体(struct

(3)引用类型:指针,切片,map集合,函数和Channel属于此类别。

  • 指针
  • 切片
  • 映射(map
  • 函数
  • channel

(4) 接口类型

4、go 语言类型分类:(参照 数据类型 | Golang 中文学习文档

(1)布尔类型(bool

布尔类型只有真值和假值。

类型描述
booltrue为真值,false为假值

提示:在 Go 中,整数 0 并不代表假值,非零整数也不能代表真值,即数字无法代替布尔值进行逻辑判断,两者是完全不同的类型。 

 (2)整型

Go 中为不同位数的整数分配了不同的类型,主要分为无符号整型与有符号整型。

序号类型和描述
uint8无符号 8 位整型
uint16无符号 16 位整型
uint32无符号 32 位整型
uint64无符号 64 位整型
int8有符号 8 位整型
int16有符号 16 位整型
int32有符号 32 位整型
int64有符号 64 位整型
uint无符号整型 至少 32 位
int整型 至少 32 位
uintptr等价于无符号 64 位整型,但是专用于存放指针运算,用于存放死的指针地址。
 (3)浮点型

IEEE-754浮点数,主要分为单精度浮点数与双精度浮点数。

类型类型和描述
float32IEEE-754 32 位浮点数
float64IEEE-754 64 位浮点数

(4)复数类型
类型描述
complex12864 位实数和虚数
complex6432 位实数和虚数
(5)字符串类型 

go 语言字符串完全兼容 UTF-8

类型描述
byte等价 uint8 可以表达 ANSCII 字符
rune等价 int32 可以表达 Unicode 字符
string字符串即字节序列,可以转换为[]byte类型即字节切片
(6)派生类型 
类型例子
数组[5]int,长度为 5 的整型数组
切片[]float64,64 位浮点数切片
映射表map[string]int,键为字符串类型,值为整型的映射表
结构体type Gopher struct{},Gopher 结构体
指针*int,一个整型指针。
函数type f func(),一个没有参数,没有返回值的函数类型
接口type Gopher interface{},Gopher 接口
通道chan int,整型通道
(7)零值 

官方文档中零值称为zero value,零值并不仅仅只是字面上的数字零,而是一个类型的空值或者说默认值更为准确。

类型零值
数字类型0
布尔类型false
字符串类型""
数组固定长度的对应类型的零值集合
结构体内部字段都是零值的结构体
切片,映射表,函数,接口,通道,指针nil
(8)nil 

nil类似于其它语言中的none或者null,但并不等同。nil仅仅只是一些引用类型的零值,并且不属于任何类型,从源代码中的nil可以看出它仅仅只是一个变量。

var nil Type

并且nil == nil这样的语句是无法通过编译的。

5、 如何在Go中声明变量?

可以使用var关键字声明变量:

var name string = "John Doe"

6、var:= 和 = 有什么区别?

  • var用于声明具有明确类型的变量。
  • :=用于声明并赋值类型由编译器推断的变量。
  • = 用于变量赋值
var name string = "John Doe"
name := "Jane Doe"
name = "Tom"

7、 如何将字符串转换为整数?

可以使用strconv.Atoi函数将字符串转换为整数:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    s := "123"
    i, err := strconv.Atoi(s)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(i)
    }
}

8、.nil关键字的作用是什么?

nil表示值的缺失,是一些引用类型的零值。

var name string
fmt.Println(name == "") // true
fmt.Println(name == nil) // false

9、什么是map?如何创建和操作map?如何在map中删除键值对?

答:map是一种哈希表,用于存储键值对map中的键是唯一的,而值可以重复

创建map的方式是使用make函数。

可以使用索引和delete函数来操作map。

//使用make函数创建map 
m := make(map[string]int)

//使用索引和delete函数来操作map
m["one"] = 1
delete(m, "one")

10、如何检查一个map中是否包含某个键?

可以使用以下语法检查map中是否包含某个键:

m := map[string]int{"one": 1}
if _, ok := m["one"]; ok {
    fmt.Println("Map contains key")
}

11、lencap有什么区别?

  • len返回数组或切片的长度。
  • cap返回数组或切片的容量。
a := make([]int, 5, 10)
fmt.Println(len(a)) // 5
fmt.Println(cap(a)) // 10

12、append函数的作用是什么?

append函数用于向切片中添加一个或多个元素:

s := make([]int, 5)
s = append(s, 1, 2, 3)

13.什么是切片(slice)?它和数组有什么区别?如何创建和操作切片?

答:切片(slice)是一个动态数组,可以在运行时自动扩容。切片和数组的主要区别在于,切片的长度是可变的,而数组的长度是固定的

创建切片的方式是使用make函数或者通过切片表达式进行创建。切片可以使用索引和切片表达式进行操作,如:s[1:3]表示从切片s中取出下标为1到下标为2的元素。

//使用make 函数创建切片
s := make([]int, 5)

14、Go 中空 struct{} 有哪些用途?

Go语言中的空struct类型struct{}不占用任何内存空间,被称为"空struct"。这种特殊的类型在Go语言中有很多用途,下面是其中一些:

  • 作为信号量(signal):一个channel可以用来传递数据,也可以用来传递信号。如果一个channel只是用来传递信号而不传递数据,可以使用空struct作为信号量。
func main() {
    ch := make(chan struct{}, 1)
    go func() {
        <-ch
        // do something
    }()
    ch <- struct{}{}
    // ...
}
  • 占位符:在一些数据结构中,需要占用一个位置,但并不需要存储实际的数据。这种情况下可以使用空struct作为占位符。
  • 集合的key:在Go语言中,可以使用map来实现集合(set)的功能。当key值不重要,只关心是否存在时,可以使用空struct作为map的key。这样可以避免分配额外的空间和降低内存占用。
type Set map[string]struct{}

func main() {
        set := make(Set)

        for _, item := range []string{"A", "A", "B", "C"} {
                set[item] = struct{}{}
        }
        fmt.Println(len(set)) // 3
        if _, ok := set["A"]; ok {
                fmt.Println("A exists") // A exists
        }
}
  • 函数参数:当不需要传递参数时,可以使用空struct作为函数参数,以避免分配不必要的内存。
  • 结构体占位符:在定义结构体时,有时候需要为未来添加的字段留出空间。这时可以使用空struct作为占位符,以避免修改已有的代码。
type Lamp struct{}

总之,空struct的主要作用是在不需要实际存储数据的情况下占用空间,从而实现一些特殊的功能。使用空struct可以避免额外的内存分配,提高程序的性能和效率。

15、 go里面的int和int32是同一个概念吗?

不是一个概念。go语言中的int的大小是和操作系统位数相关的,如果是32位操作系统,int类型的大小就是4字节。如果是64位操作系统,int类型的大小就是8个字节。除此之外uint也与操作系统有关,占字节与int类型情况一致。

而int后有数字的话,占用空间大小是固定的:int8占1个字节,int16占2个字节,int32占4个字节,int64占8个字节。

16、如何交换 2 个变量的值?

对于变量而言a,b = b,a; 对于指针而言*a,*b = *b, *a

 17、2 个 nil 可能不相等吗?

可能不等。interface在运行时绑定值,只有值为nil接口值才为nil,但是与指针的nil不相等。举个例子:

var p *int = nil

var i interface{} = nil

if(p == i){ fmt.Println("Equal") }

两者并不相同。总结:两个nil只有在类型相同时才相等

18、如何比较两个切片是否相等?

(1)使用 == 运算符

直接比较两个切片是否相等,要求长度和元素完全一致

s1 := []string{"a", "b", "c"}
s2 := []string{"a", "b", "c"}
fmt.Println(s1 == s2) // true(仅当切片指向同一底层数组时有效)

注意== 运算符在 Go 中比较的是切片的指针、长度和容量,只有当两个切片指向同一底层数组且内容完全一致时才返回 true。如果底层数组不同但内容相同,== 会返回 false

(2)使用 reflect.DeepEqual

通过反射包深度比较切片内容:

import "reflect"

s1 := []string{"a", "b", "c"}
s2 := []string{"a", "b", "c"}
fmt.Println(reflect.DeepEqual(s1, s2)) // true

适用场景:需要比较切片内容是否完全一致(包括元素顺序和值)。

(3)自定义比较函数

手动遍历切片比较每个元素:

func equalSlices(s1, s2 []string) bool {
    if len(s1) != len(s2) {
        return false
    }
    for i := range s1 {
        if s1[i] != s2[i] {
            return false
        }
    }
    return true
}

s1 := []string{"a", "b", "c"}
s2 := []string{"a", "B", "c"}
fmt.Println(equalSlices(s1, s2)) // false(区分大小写)

扩展性:可以在此基础上添加逻辑,例如忽略大小写、去空格等。

(4)使用第三方库

例如 go-cmp 库的 cmp.Equal 函数:

import "github.com/google/go-cmp/cmp"

s1 := []string{"a", "b", "c"}
s2 := []string{"a", "b", "c"}
fmt.Println(cmp.Equal(s1, s2)) // true

优势:支持更复杂的比较逻辑(如忽略字段、自定义比较器)。

19、go slice是怎么扩容的?

  • 1.7版本
    • 如果当前容量小于1024,则判断所需容量是否大于原来容量2倍,如果大于,当前容量加上所需容量;否则当前容量乘2。
    • 如果当前容量大于1024,则每次按照1.25倍速度递增容量,也就是每次加上cap/4。
  • 1.8版本:Go1.18不再以1024为临界点,而是设定了一个值为256的threshold,以256为临界点;超过256,不再是每次扩容1/4,而是每次增加(旧容量+3*256)/4;
    • 当新切片需要的容量cap大于两倍扩容的容量,则直接按照新切片需要的容量扩容;
    • 当原 slice 容量 < threshold 的时候,新 slice 容量变成原来的 2 倍;
    • 当原 slice 容量 > threshold,进入一个循环,每次容量增加(旧容量+3*threshold)/4。

20、new和make的区别?

  • new只用于分配内存,返回一个指向地址的指针。它为每个新类型分配一片内存,初始化为0且返回类型*T的内存地址,它相当于&T{}
  • make只可用于slice,map,channel的初始化,返回的是引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值