Golang
2022-09-16
# tree -L 1 -d .
.
├── api
├── doc
├── lib
├── misc
├── src
└── test
6 directories
# tree -L 1 -d src/
src/
├── archive
├── bufio
├── builtin
├── bytes
├── cmd
├── compress
├── container
├── context
├── crypto
├── database
├── debug
├── embed
├── encoding
├── errors
├── expvar
├── flag
├── fmt
├── go
├── hash
├── html
├── image
├── index
├── internal
├── io
├── log
├── math
├── mime
├── net
├── os
├── path
├── plugin
├── reflect
├── regexp
├── runtime
├── sort
├── strconv
├── strings
├── sync
├── syscall
├── testdata
├── testing
├── text
├── time
├── unicode
├── unsafe
└── vendor
46 directories
tree -L 2 -d src/net/
src/net/
├── http
│ ├── cgi
│ ├── cookiejar
│ ├── fcgi
│ ├── httptest
│ ├── httptrace
│ ├── httputil
│ ├── internal
│ ├── pprof
│ └── testdata
├── internal
│ └── socktest
├── mail
├── rpc
│ └── jsonrpc
├── smtp
├── testdata
├── textproto
└── url
19 directories
Golang
2022-09-13
awesome-go 上面列出来的项目:
- jakehl/goid
- Generate and Parse RFC4122 compliant V4 UUIDs.
- twharmon/gouid
- Generate cryptographically secure random string IDs with just one allocation.
- aidarkhanov/nanoid
- A tiny and efficient Go unique string ID generator.
- muyo/sno
- Compact, sortable and fast unique IDs with embedded metadata.
- oklog/ulid
- Go implementation of ULID (Universally Unique Lexicographically Sortable Identifier).
- uniq - No hassle safe, fast unique identifiers with commands.
- agext/uuid
- Generate, encode, and decode UUIDs v1 with fast or cryptographic-quality random node identifier.
- gofrs/uuid
- Implementation of Universally Unique Identifier (UUID). Supports both creation and parsing of UUIDs. Actively maintained fork of satori uuid.
- google/uuid
- Go package for UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
- edwingeng/wuid
- An extremely fast globally unique number generator.
- rs/xid
- Xid is a globally unique id generator library, ready to be safely used directly in your server code.
我自己又在 GitHub 上搜罗了几个:
package main
import (
"os/exec"
guuid "github.com/google/uuid"
suuid "github.com/satori/go.uuid"
)
func UseGoogle() string {
id := guuid.New()
return id.String()
}
func UseSatori() string {
id := suuid.NewV4()
return id.String()
}
func UseUuidgen() string {
id, _ := exec.Command("uuidgen").Output()
return string(id)
}
func main() {
fmt.Println("Google UUID:", UseGoogle())
fmt.Println("Satori UUID:", UseSatori())
fmt.Println("Uuidgen UUID:", UseUuidgen())
}
Golang
2022-09-13
得知了 Go 谚语这么个东西,搜索一番,找到:
- https://go-proverbs.github.io/
- https://github.com/jboursiquot/go-proverbs
- https://www.youtube.com/watch?v=PAAkCSZUG1c
原来是类似 Python 之禅(import this)一样的东西。
- Don't communicate by sharing memory, share memory by communicating. 别通过共享内存通信,要通过通信共享内存。
- Concurrency is not parallelism. 并发不是并行。
- Channels orchestrate; mutexes serialize.
- The bigger the interface, the weaker the abstraction. 接口越大, 抽象越弱。
- Make the zero value useful.
interface{} says nothing.
- Gofmt's style is no one's favorite, yet gofmt is everyone's favorite. 别争论风格问题,不管喜不喜欢,用 gofmt 就是了。
- A little copying is better than a little dependency. 少量的复制好过引入新的依赖。
- Syscall must always be guarded with build tags.
- Cgo must always be guarded with build tags.
- Cgo is not Go. 别用 cgo。
- With the unsafe package there are no guarantees. 慎用 unsafe 包(安全无保障)
- Clear is better than clever. 清晰的代码比聪明的代码好。
- Reflection is never clear. 慎用反射(代码不清晰)。
- Errors are values.
- Don't just check errors, handle them gracefully.
- Design the architecture, name the components, document the details.
- Documentation is for users. 文档是给用户的(注意代码本身的可读性)。
- Don't panic. 不要滥用
panic。
Golang Viper
2022-07-22
package main
import (
"fmt"
"os"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
func main() {
// 1. 设置 Viper 配置
viper.SetConfigName("config") // 配置文件名(不带后缀)
viper.AddConfigPath(".") // 配置文件路径
viper.SetConfigType("yaml") // 配置文件类型
viper.AutomaticEnv() // 自动读取环境变量
// 2. 设置命令行参数
pflag.String("name", "", "project name")
pflag.String("host", "", "host address")
pflag.String("port", "", "port number")
pflag.String("config", "./config.yaml", "config file") // 配置文件参数
pflag.Parse()
viper.BindPFlags(pflag.CommandLine) // 将命令行参数绑定到 Viper
// 3. 读取配置文件
if configFile := viper.GetString("config"); configFile != "" {
fmt.Println(configFile)
if err := viper.ReadInConfig(); err != nil {
fmt.Fprintf(os.Stderr, "读取配置文件失败:%v\n", err)
os.Exit(1)
}
}
// 4. 读取配置项
projectName := viper.GetString("name")
port := viper.GetInt("port")
fmt.Printf("ProjectName: %s, Port: %d\n", projectName, port)
}
name: hello
host: 10.10.0.172
port: 9090
- 支持环境变量、命令行参数、配置文件。
- 支持多种配置文件,包括 JSON,YAML,TOML,INI 等。
- 支持监控配置文件的变化,会自动加载新的配置。
- 支持从远程加载配置,比如 etcd、zk、consul、redis 等,
也可以通过 RemoteProvider 接口自定义远程数据源:
type RemoteProvider interface {
Set(key string, value []byte) error
Watch(key string) (chan *RemoteResponse, chan error)
Get(key string) ([]byte, error)
}
Golang
2022-07-20
通过对 key 做哈希,来实现 Redis 服务器的分片。
用这个例子来演示这个小库的用法:
package main
import (
"crypto/rand"
"encoding/base64"
"fmt"
"log"
"time"
"github.com/go-redis/redis"
"github.com/serialx/hashring"
)
func RandomString(length int) (string, error) {
b := make([]byte, length)
_, err := rand.Read(b)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(b)[:length], nil
}
func main() {
redisServers := map[string]int{
"redis1:6379": 200,
"redis2:6379": 100,
}
redisClients := []*redis.Client{}
for uri, _ := range redisServers {
redisClients = append(redisClients, redis.NewClient(&redis.Options{Addr: uri}))
}
log.Println(redisServers)
ring := hashring.NewWithWeights(redisServers)
stat := map[string]int{}
for uri, _ := range redisServers {
stat[uri] = 0
}
for i := 0; i < 100; i++ {
randstr, _ := RandomString(8)
key := "test:randkey:" + randstr
node, ok := ring.GetNode(key)
if !ok {
log.Panicf("cannot assign a redis client by key: %#v", key)
}
log.Printf("%s -> %s", key, node)
stat[node]++
var client *redis.Client
for _, _client := range redisClients {
if node == _client.Options().Addr {
client = _client
break
}
}
if client == nil {
log.Panicf("redis client assigned error: %#v", node)
}
client.Set(key, 1, time.Minute)
}
fmt.Println(stat)
}
Golang
2022-07-19
https://github.com/bits-and-blooms/bloom/v3

package main
import (
"fmt"
"github.com/bits-and-blooms/bloom/v3"
)
func main() {
filter := bloom.New(1000000, 5)
filter.Add([]byte("apple"))
filter.Add([]byte("banana"))
filter.Add([]byte("orange"))
fmt.Println(filter.Test([]byte("apple")))
fmt.Println(filter.Test([]byte("banana")))
fmt.Println(filter.Test([]byte("orange")))
fmt.Println(filter.Test([]byte("grape")))
fmt.Println(filter.Test([]byte("watermelon")))
}
Golang GUI
2022-06-20
明显,fyne 遥遥领先。
Golang
2022-06-10
type Weekday int
const (
Sunday Weekday = iota // 0
Monday // 1
Tuesday // 2
Wednesday // 3
Thursday // 4
Friday // 5
Saturday // 6
)
func (day Weekday) String() string {
names := [...]string{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
}
if day < Sunday || day > Saturday {
return "Unknown"
}
return names[day]
}
type FileSizeUnit int
const (
_ = iota // 忽略第一个值 0,让后续常量从 1 开始递增
KB FileSizeUnit = 1 << (10 * iota) // 1 << (10*1) = 1 << 10 = 1024
MB // 1 << (10*2) = 1 << 20 = 1048576
GB // 1 << (10*3) = 1 << 30 = 1073741824
TB // 1 << (10*4) = 1 << 40 = 1099511627776
)
package main
import "fmt"
func main() {
{
const (
a = iota
b
c
)
fmt.Printf("%+v\n", []int{a, b, c})
// [0 1 2]
}
{
const (
a = 1
b = iota
c
)
fmt.Printf("%+v\n", []int{a, b, c})
// [1 1 2]
}
{
const (
a = 1
b = 2
c = iota
)
fmt.Printf("%+v\n", []int{a, b, c})
// [1 2 2]
}
{
const (
a = 1
b = iota
c = iota
)
fmt.Printf("%+v\n", []int{a, b, c})
// [1 1 2]
}
}
总结
- 首次出现是这个常量块中变量的顺序(0 开始)
- 后面的常量如果没有定义,就表示是按照前面的常量定义来,只是 iota 代表的值 + 1 了
- 如果想跳过一个值,可以使用下划线
Golang
2022-04-28
dlv 是 Golang 生态中一种常见的调试工具,我感觉有点类似 gdb。本文描述其基本用法。
Golang GC
2022-04-11
相信 Golang 开发者可能前段时间见过两位大佬关于 Golang 性能的技术讨论(撕X),其中一个很重要的点就是涉及 Golang GC 对性能的影响。
我之前的开发经验几乎全部集中于 PHP,JS,Python 等脚本型语言,较少需要涉及 GC(只有几次涉及服务内存占用的时候检查过 GC)。
接触到 Golang 之后,如果不去研究 GC 可能很多疑问是无法解决的,很多时候的优化也和 GC 密切相关。