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 密切相关。
Golang
2022-04-10
2007 Robert Griesemer、Rob Pike 和 Ken Thompson 三位巨头都在谷歌任职,开始设计一门全新的语言。
Release |
Status |
Release date |
Maintenance end |
go1 |
End-of-Life |
2012-03-28 |
2013-12-01 |
go1.1 |
End-of-Life |
2013-05-13 |
2014-06-18 |
go1.2 |
End-of-Life |
2013-12-01 |
2014-12-10 |
go1.3 |
End-of-Life |
2014-06-18 |
2015-08-19 |
go1.4 |
End-of-Life |
2014-12-10 |
2016-02-17 |
go1.5 |
End-of-Life |
2015-08-19 |
2016-08-15 |
go1.6 |
End-of-Life |
2016-02-17 |
2017-02-16 |
go1.7 |
End-of-Life |
2016-08-15 |
2017-08-24 |
go1.8 |
End-of-Life |
2017-02-16 |
2018-02-16 |
go1.9 |
End-of-Life |
2017-08-24 |
2018-08-24 |
go1.10 |
End-of-Life |
2018-02-16 |
2019-02-25 |
go1.11 |
End-of-Life |
2018-08-24 |
2019-09-03 |
go1.12 |
End-of-Life |
2019-02-25 |
2020-02-25 |
go1.13 |
End-of-Life |
2019-09-03 |
2020-08-11 |
go1.14 |
End-of-Life |
2020-02-25 |
2021-02-16 |
go1.15 |
End-of-Life |
2020-08-11 |
2021-08-16 |
go1.16 |
End-of-Life |
2021-02-16 |
2022-03-15 |
go1.17 |
End-of-Life |
2021-08-16 |
2022-08-02 |
go1.18 |
End-of-Life |
2022-03-15 |
2023-02-01 |
go1.19 |
Maintenance |
2022-08-02 |
Q3 2023 |
go1.20 |
Current |
2023-02-01 |
Q1 2024 |
go1.21 |
Planned |
Q3 2023 |
Q3 2024 |
1.16 及以前的版本
我开始学习 Golang 的时候,已经是 1.5 和 1.6 版本了,更早的版本只需要对重大特性引入时间做一个简单了解。
现在主要的开发版本已经升级到 1.18 和 1.20。
- 1.0
- 第一个正式版本,核心特性都已经包含在里面,承诺以后语法不会发生不兼容变化
- 至今为止,承诺都实现了。后面的版本几乎很少有激动人心的功能,绝大多数时候都是各种改进
- 1.1
- 1.2
- 支持
slice[low:high:max]
语法
- 1.4
for range
语法引入
- 1.5
- 实现自举
- 1.9
type alias
语法引入
- 1.11
- Go Modules 引入
- 1.12
- 开始支持 TLS 1.3
- 需要通过
GODEBUG=tls13=1
开启(不能通过 tls Config MaxVersion 限制版本)
- 0-RTT 不被支持(到 2023 年,依然没有提供支持)
- 1.13
- TLS 1.3 默认开启
- 1.14
- TLS 1.3 成为默认选项,并且无法通过 GODEBUG 关闭
- 异步可抢占 goroutine
- 1.16
- Go Modules 成为默认(
GO111MODULE = on
)
- 支持将静态文件打包进可执行文件(
//go:embed
)
- 弃用 io/ioutil
参考:
1.17
- Module graph pruning(依赖图修剪)
- 切片转数组指针
参考:
1.18
- 泛型(Golang 发布以来最大的语法变更)
- fuzzing(模糊测试)
- TLS 客户端默认版本改为 1.2
参考:
1.19
没有特别值得关注的的改动。
参考:
1.20
参考:
1.21
min
, max
和 clear
- 循环变量捕获 (loop variable capture)
参见:2023/07/05,Go 1.21 for
语义变更
- 标准库:
log/slog
, slices
, maps
, cmp
参考:
WebDev Golang Gin Vue ElementUI
2022-04-03
:) 本文正在编辑中,暂时不提供浏览...
Golang
2022-04-02
- 语法简单
- 确实没有很多语言特性,容易上手,但说什么大道至简,Less is more 等价值观就有点扯了。
- 静态类型、强类型、编译型语言
- 性能
- 并发:自带的协程实现(
goroutine
+ channel
)在开发效率和性能之间达成了一个不错的平衡,非常优秀
- 跨平台
- 接口,反射,GC
- C 嵌入
- 便于工程化:工具链齐全,代码规范严格
- 没有历史负担:但是向前兼容的承诺也是
- Go1 兼容性承诺(最重要特性之一):但是也令人担忧,时间一长,可能就有太重的包袱
- 基于消息传递的通信机制
- 核心开发团队名气非常大
- robert griesemer
- rob pike
- ken thompson
- russ cox
- 生态:有大公司站台,有杀手级项目(Docker, K8S 等)
存在的问题
- 异常处理的设计
- 标准库相对太薄弱
- 生态:缺乏主流框架
- 包管理机制上存在的问题
- 没有泛型(1.18 以前)
场景