Go


题目

如何高效地拼接字符串

Go 语言中,字符串是只读的,也就意味着每次修改操作都会创建一个新的字符串。如果需要拼接多次,应使用 strings.Builder,最小化内存拷贝次数

strings.Builder 是 Golang 中的一个用于高效构建字符串的类型,使用了一个循环缓冲区来存储字符数据,避免了频繁的内存分配和拷贝操作,尤其适用于频繁拼接字符串的场景

构造字符串的最大代价就是copy内存

var a strings.Builder
for i:=0;i<1000;i++ {
    a.WriteString("a")
}
fmt.Println(a.String())

什么是 rune 类型

  • ASCII 码只需要 7 bit 就可以完整地表示,但只能表示英文字母在内的128个字符,为了表示世界上大部分的文字系统,发明了 Unicode, 它是ASCII的超集,包含世界上书写系统中存在的所有字符,并为每个代码分配一个标准编号(称为Unicode CodePoint),在 Go 语言中称之为 rune,是 int32 类型的别名。
  • Go 语言中,字符串的底层表示是 byte (8 bit) 序列,而非 rune (32 bit) 序列。例如下面的例子中 语 和 言 使用 UTF-8 编码后各占 3 个 byte,因此 len(“Go语言”) 等于 8,当然我们也可以将字符串转换为 rune 序列。
fmt.Println(len("Go语言")) // 8
fmt.Println(len([]rune("Go语言"))) // 4

如何判断 map 中是否包含某个 key ?

if val, ok := dict["foo"]; ok {
    //do something here
}

Go 支持默认参数或可选参数吗?支持方法重载吗?

  • go不支持类似 Python 的默认参数,也不支持可选参数;但是支持不定长的参数;
  • go不支持类似 Java 的方法重载;
func sum(numbers ...int) int {
    total := 0
    for _, num := range numbers {
        total += num
    }
    return total
}

func main() {
    fmt.Println(sum(1, 2, 3, 4, 5)) // 输出:15
    fmt.Println(sum(1, 2, 3)) // 输出:6
    fmt.Println(sum(1)) // 输出:1
}

defer 的执行顺序

  • 以类似栈的的形式执行,简单来说,是从下往上执行 ↑;最后定义的defer最先执行;

  • defer 在 return 之后执行,而且 defer 可以修改返回值;

    • 但是注意:【匿名返回值】和【命名返回值】是有区别的;见下面的例子:
    • 解释:
      • 对于【匿名返回值】,执行return之后,go会创建一个临时变量保存返回值,而在defer中的修改并没有影响这个临时变量,所以最终的效果是defer中的语句并没有对返回值产生影响;
      • 对于【命名返回值】,并不会创建这样一个返回值,自始至终都是同一个值,所以defer中的修改会影响最终的返回值;
func test() int {
    i := 0
    defer func() {
        fmt.Println("defer1")
    }()
    defer func() {
        i += 1
        fmt.Println("defer2")
    }()
    return i
}

func main() {
    fmt.Println("return", test())
}
// defer2
// defer1
// return 0

字符串打印 %v %#v %+v 的区别

fmt.Printf("%v\n", Person{name: "John", age: 32, address: "New York", sex: true})
fmt.Printf("%+v\n", Person{name: "John", age: 32, address: "New York", sex: true})
fmt.Printf("%#v\n", Person{name: "John", age: 32, address: "New York", sex: true})
// result
// {name:John age:32 address:New York sex:true}
// {name:John age:32 address:New York sex:true}
// main.Person{name:"John", age:32, address:"New York", sex:true}

a := "John"
fmt.Printf("%v\n",a)
fmt.Printf("%+v\n",a)
fmt.Printf("%#v\n",a)
// result
// John
// John
// "John"

占位符拓展

%c 字符,如果有数字按照ASCALL转成字符

%d 十进制数字,如果有字符转换成

%b 二进制,输出字符或者数字的二进制

%T 类型,打印字符或者数字的类型

Go 语言的局部变量分配在栈上还是堆上?

在 Go 语言中,局部变量通常分配在栈上。栈是一种动态分配的数据结构,它用于存储函数调用时的临时数据。当一个函数被调用时,会在栈上分配一定的空间来存储函数的局部变量、参数和返回地址等信息。当函数返回时,这些空间会被自动释放。

堆是另一种动态分配的数据结构,它用于存储需要长期存在的数据,例如动态分配的内存。在 Go 语言中,可以使用 new 关键字或 make 函数来在堆上分配内存。

2 个 interface 可以比较吗 ?

在 Go 语言中,interface 是一种抽象类型,它定义了一组方法签名,但不包含具体的实现。interface 类型的值可以包含任何实现了该接口的类型的实例。

由于 interface 类型的值可以包含不同类型的实例,因此不能直接比较两个 interface 类型的值是否相等。这是因为不同类型的实例可能具有不同的内部结构和行为,无法直接进行比较。

var a interface{} = Person{"Alice", 25}
var b interface{} = Person{"Bob", 30}
// 类型断言表达式
if c, d := a.(Person), b.(Person); c == d {
    fmt.Println("两个 Person 类型的实例相等")
}

2 个 nil 可能不相等吗?

在 Go 语言中,nil 是一个预定义的空值,表示没有值或未初始化的变量。nil 是一个唯一的值,对于任何类型的变量,nil 都表示空值。

因此,对于任何类型的变量,两个 nil 值都是相等的。这是因为 nil 是一个特殊的常量,它的值在整个程序中是唯一的。

简述 Go 语言GC(垃圾回收)的工作原理

Go 语言的垃圾回收(Garbage Collection,GC)是由其运行时系统自动管理的,它使用了一种三色标记法(Three-color Mark-and-Sweep)来进行垃圾回收。

三色标记法的基本思想是将内存中的对象标记为三种颜色:白色、黑色和灰色。白色表示未被访问过的对象,黑色表示已被访问过并且不会再被回收的对象,灰色表示已被访问过但其引用的对象还未被访问过的对象。

在垃圾回收过程中,首先将所有对象标记为白色。然后,从根对象(例如全局变量和栈帧中的指针)开始,遍历引用的对象,并将它们标记为灰色。接着,再次遍历灰色对象,将它们引用的对象也标记为灰色,并将已经访问过的灰色对象标记为黑色。最后,遍历所有剩余的白色对象,并将它们标记为可回收的垃圾。

在垃圾回收过程中,Go 语言的运行时系统会暂停整个程序的运行,以便进行垃圾回收。这可能会导致短暂的程序暂停,但 Go 语言的设计目标是尽量减少这种暂停的时间,以提高程序的性能。

Go 语言的垃圾回收是自动进行的,程序员不需要手动管理内存。这使得 Go 语言在开发高效、可靠的程序时更加方便和高效。

函数返回局部变量的指针是否安全?

在 Go 语言中,函数返回局部变量的指针是不安全的,因为局部变量的内存是在函数调用结束后被释放的。

如果函数返回了局部变量的指针,那么该指针指向的内存已经被释放,可能会导致程序崩溃或出现未定义的行为。

为了避免这种情况,应该尽量避免在函数中返回局部变量的指针。如果必须返回指针,可以考虑使用new关键字在堆上分配内存,并在使用完毕后使用delete关键字释放内存。但是,这种方式也需要谨慎使用,因为在堆上分配和释放内存会增加程序的开销,并且可能会导致内存泄漏问题。

总之,在编写 Go 语言程序时,应该尽量避免在函数中返回局部变量的指针,以保证程序的安全性和可靠性。

学习源码

分享如何阅读Go源码

go操作mongo不生效

基本上都需要使用结构体来传递参数,结构体定义需要注意一下几点

  1. 结构体变量名大写!!!
  2. 结构体变量要和数据表中的字段一一对应
  3. 加上bson:"ip",不知道是啥用
type IpTimeStruct struct {
    Ip          string `bson:"ip"`
    Update_time int64  `bson:"update_time"`
}

打印变量的类型

import "reflect" // 导入
fmt.Println(reflect.TypeOf(curr))

go 操作 redis 耗时测试

img

疑问

go程序:使用命令行、运行都回出现报错

img

img

使用Debug模式,打包好时候运行就不会出现

img

img

channel buffer


文章作者: Nico
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Nico !
  目录