跳转至

Golang 编程实践

Go 语言中的 nil 和变量初始化规则

在 Go 语言中,nil 是一个特殊的值,表示“没有值”或者“无效值”。它通常用于表示指针、接口、切片、映射、通道等类型的零值。然而,Go 对不同类型的变量初始化有严格的规则,尤其是对未指定类型的变量,使用 nil 时需要特别注意。

Go 语言中 map 的内存分配与容量管理

在 Go 语言中,map 类型与切片(slice)在内存分配和容量管理方面有一些不同。你可以使用 make 函数初始化一个 map 并指定其初始容量,但与切片不同的是,map 并没有提供类似于 cap 的函数来查询其容量。本文将详细介绍 map 的内存分配机制、容量管理以及为什么不能使用 cap 函数来获取 map 的容量。

Go 语言中字符串与 []byte 之间的转换与性能优化

在 Go 语言中,字符串与 []byte(字节切片)是两种常见的数据类型,它们之间的转换是频繁的操作。由于字符串是不可变的(immutable),而 []byte 是可变的(mutable),因此在许多情况下需要进行相互转换。比如,字符串需要作为字节流传递,或字节流需要转换为字符串进行处理。

然而,这种转换并非没有代价,尤其是当涉及到内存分配时。每次从字符串转换到 []byte,或者从 []byte 转回字符串,都可能产生额外的内存消耗。因此,了解如何避免不必要的内存分配和如何高效地进行转换是至关重要的。

Go 语言中字符串与 rune 的迭代与非 UTF-8 字符的处理

在 Go 语言中,字符串是由 UTF-8 编码的字符序列构成的,而字符串中的每个字符实际上是由一个或多个 rune(即 Unicode 代码点)组成的。Go 的 for range 循环提供了便捷的方式来遍历字符串中的字符,它会将每个字符解析为 rune 类型。然而,在某些情况下,特别是处理包含非 UTF-8 编码字节的字符串时,直接使用 for range 可能会导致一些问题。

Golang 中的意外变量幽灵(Accidental Variable Shadowing)

在 Go 语言中,短变量声明(:=)是一种非常便捷的语法,它可以让我们在声明变量时简洁地赋值。然而,使用短变量声明时,如果局部作用域中和外部作用域的变量同名,可能会发生 意外的变量幽灵(Accidental Variable Shadowing) 问题,导致局部变量的修改并不会影响到外部变量的值。

Go 切片中删除元素的两种方法对比

在 Go 语言中,切片是一个非常常用的数据结构。当我们需要从切片中删除某个元素时,通常有两种实现方法:

  1. 使用 append 方法删除元素。
  2. 使用替换删除法。

本文将对这两种方法进行对比,分析各自的优缺点,并帮助你根据具体需求选择合适的实现方式。

关于 golang 的条件编译个人实践

在 Go 中,当你遇到 “build constraints exclude all Go files” 错误时,意味着在某个包中没有符合当前构建条件的文件。

核心是诊断触发的条件

项目中遇到一个服务需要调用 Cplus 开发的库函数实现某些功能,但是仅提供了 Windows 和 Linux 两个平台,导致我们无法在 Darwin 环境运行该服务,算是业务驱动我去更精细化的了解技术了。

我期望的条件编译规则如下:

  1. Linux 和 Windows 编译包含库函数的代码;
  2. Darwin 不编译;
  3. 可以选择是否调用库函数;

规则 1, 2 可以使用平台条件编译实现:

// 规则一触发
//go:build !darwin

// 规则二触发
//go:build darwin

规则 3 需要依赖与 -tags 配置进一步控制编译结果

// 符合规则 1, 2 且允许规则 3 时编译
//go:build !darwin && tag01

// 符合规则 2 或不满足规则 3
//go:build darwin || !tag

这样配置已经没有问题了,但是仍然提示 “build constraints exclude all Go files” 错误?

我们可以使用 go list 命令来查看哪些文件被包括在内以及哪些被排除:

go list -tags ${TAG_NAME} -json ${PACKAGE_NAME}

示例输出如下:

{
    "Dir": "",
    "ImportPath": "",
    "Name": "bitanswer",
    "Files": [],
    "GoFiles": [],
    "IgnoredGoFiles": [
        "file1.go",
        "file2.go"
    ],
    "GoFilesExclude": [
        "file1.go",
        "file2.go"
    ]
}

结论

golang 文件夹命名也有条件编译的功能,当文件夹命名符合 filename_os 时,文件中的 //go:build 规则会失效。

我对 Context 包的理解

引言

讲真的,我一直不明白 go 的 context 怎么用,之前在用 Java 开发时就不清楚,所以这次专门花时间把 go 的 context 弄清楚。

我记得第一次接触 context 时,文档上说这个是用来做并发控制的,可以设置超时时间,超时就会快快速返回,可以携带一些信息,在生命周期中共享。生命周期这个概念很重要,我们在开发时需要掌控程序的生命周期。

我们不能简单的认为只要函数中带着 context 参数往下传递就可以做到超时取消,快速返回,其实这是一个错误的思想,其取消机制采用的也是通知机制,但出的透传并不会起作用,比如你这么写代码:

func main()  {
    ctx,cancel := context.WithTimeout(context.Background(),10 * time.Second)
    defer cancel()
    go Monitor(ctx)

    time.Sleep(20 * time.Second)
}

func Monitor(ctx context.Context)  {
    for {
        fmt.Print("monitor")
    }
}

我们需要学会正确的使用 context。