分类 "Golang" 下的文章

公司大量使用微服务框架 go-micro,但框架作者已不再维护低版本(新版本已经商业化),只能自己动手了。

起因是我用 Go 1.16 编译,启动报错:

panic: qtls.ConnectionState not compatible with tls.ConnectionState

goroutine 1 [running]:
github.com/lucas-clemente/quic-go/internal/handshake.init.0()
        /go/pkg/mod/github.com/lucas-clemente/quic-go@v0.12.1/internal/handshake/unsafe.go:17 +0x118

阅读全文

阅读本文大约需要 40 分钟。

上一篇文章 《大白话讲讲 Go 语言的 sync.Map(一)》 讲到 entry 数据结构,原因是 Go 语言标准库的 map 不是线程安全的,通过加一层抽象回避这个问题。

当一个 key 被删除的时候,比如李四销户了,以前要撕掉小账本,现在可以在大账本上写 expunged,

对,什么也不写也是 OK 的。也就是说,

entry.p 可能是真正的数据的地址,也可能是 nil,也可能是 expunged。

阅读全文

阅读本文大约需要 4.25 分钟。

程序是枯燥乏味的。

在讲 sync.Map 之前,我们先说说什么是 map(映射)。

我们每个人都有身份证号码,如果我需要从身份证号码查到对应的姓名,用 map 存储是非常合适的。

map[000...001] = 张三
map[000...002] = 李四
...
map[999...993] = 钱五

身份证号码有 18 位,如果要知道 111...002 这个人叫什么名字,没有 map 我只能从 000...001 一个一个往下查找,效率是非常低的。

阅读全文

nil 是什么?

可以看看官方的描述,在 buildin/buildin.go 里:

// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

nil 是一个预先声明的标识符,代表指针、通道、函数、接口、哈希表或切片的零值。

OK,回到问题,nil 能比较自己吗?

package main

import "fmt"

func main() {
    fmt.Println(nil == nil)
}

// # command-line-arguments
// ./main.go:6:18: invalid operation: nil == nil (operator == not defined on nil)

没有具体的类型,编译器懵逼了说没办法比较。

slice 什么时候是 nil ?

看看下面的代码:

var slice = []string{}
fmt.Println(slice == nil) // false

type GoSlice struct {
        ptr unsafe.Pointer
    len int
    cap int
}
s := (*GoSlice)(unsafe.Pointer(&a))
s.ptr = nil
fmt.Println(s == nil) // true

神奇,切片底层指针为 nil 的时候,就是一个 nil 切片。map、channel、func 也是类似的。

nil 和 interface 一起使用的坑

继续看代码:

type A interface {}
type a struct {}

func Foo() A {
    var data *a // nil
    return data
}

fmt.Println(Foo() == nil) // false

嗯,坑得体无完肤。很反人类!接口为 nil,必须是类型和值同时为 nil,才能等于 nil,无聊的知识又增加了:)

坑一:迭代时协程引用索引和值

先看看下面的例子,你知道最终输出的结果是什么吗?

package main

import (
    "fmt"
    "time"
)

func main() {
    var m = []int{1, 3, 5}
    for i, v := range m {
        go func() {
            fmt.Println(i, v)
        }()
    }
    time.Sleep(time.Second)
}

阅读全文

今天分享的内容比较基础,准确地说是 Go 的语言特性——命名、匿名返回值。

先看下面的例子,猜测会输出什么?

package main

func main() {
    println(A())
    println(B())
}

func A() int {
    var i int
    defer func() {
        i = i + 3
    }()
    return i
}

func B() (i int) {
    defer func() {
        i = i + 3
    }()
    return i
}

|

(想好答案再滑下来)

|

|

|

|

|

|

|

|

|

|

正确答案:0 3。

A 和 B 两个函数的区别在于,B 的函数返回值是命名的,所以 defer 函数执行的修改,会作用到 B 本身;

而 A 函数返回值是匿名的,取决于 return 的时候求出来的值。

翻遍整个 GitHub , Golang 中文转拼音类库, 怎么就这么难找呢? 于是我造了一个轮子: 中文转拼音类库. 目前来说应该是最好用的了.

GitHub 传送门: https://github.com/Lofanmi/pinyin-golang

如果说基于汉字拼音字典, 逐个汉字替换, 也是可以转换的, 但是碰到多音字就很麻烦了. 而基于词库, 最起码可以解决大多数的多音字的转换, 人名姓氏的转换.

最开始我用了 CC-CEDICT 词典, 基于词组的长度, 以及英文释义的丰富程度, 来决定替换的优先级, 词组越长优先替换, 英文解释越丰富, 说明它越常用, 拥有更高的优先级, 后来发现它很多汉字都没有收录, 更别说生僻字了.

阅读全文