首页
网站导航
关于
Search
1
解决Typecho Joe主题访问fastly.jsdelivr.net速度慢的方案 | 快速优化技巧
2,252 阅读
2
解决WSL2内存不释放问题的最佳指南
1,529 阅读
3
如何在 Typecho Joe 主题的文章中增加目录
1,186 阅读
4
GO语言环境的搭建教程 - 完全指南
1,042 阅读
5
如何解决Win11电脑桌面上方显示横线问题 | 窗口11教程
1,028 阅读
默认分类
编程语言
GO语言
PHP
Node
javascript
html
rust
java
Css
Python
资源分享
chrome插件
阅读思考
运维架构
redis
Nginx
linux
memcached
mongodb
mysql
windows
docker
k8s
Mq
apache
CI
Git
swoole
elk
系统设计
thinkPhp
beego
登录
Search
标签搜索
重要
go基础
git 命令
go包
phpstorm
sublime
thinkphp6
mysql问题
软件分享
redis命令
php基础
thinkphp3.2
php第三扩展包
小蚯蚓博客
累计撰写
335
篇文章
累计收到
48
条评论
首页
栏目
默认分类
编程语言
GO语言
PHP
Node
javascript
html
rust
java
Css
Python
资源分享
chrome插件
阅读思考
运维架构
redis
Nginx
linux
memcached
mongodb
mysql
windows
docker
k8s
Mq
apache
CI
Git
swoole
elk
系统设计
thinkPhp
beego
页面
网站导航
关于
搜索到
62
篇与
的结果
2023-12-24
Go调用SO动态库文件的两种方式
本文章,介绍 go 调用 so 里的函数。 生成 so 文件 首先编写 add.c 源代码,里面有个简单的 add 函数,用于加法运算。 #include "stdio.h" int add(int a,int b) { printf("a+b=%d\n", a+b); return a+b; } 然后生成 so 文件 gcc -fPIC -shared -o add.so add.c 方式 1-通过 cgo 调用 思路是,编写 c 代码调用 so 库,然后 go 再调用 c 代码。 c 调用 so 文件 同一个目录,创建 goLoadSo.c 文件,内容如下,里面加载刚刚生成的 ./add.so #include <stdio.h> #include <dlfcn.h> int main(){ // 手动加载指定位置的so动态库 void* handle = dlopen("./add.so",RTLD_LAZY); int (*add)(int a,int b); // 根据动态链接库操作句柄与符号,返回符号对应的地址 add = dlsym(handle,"add"); int sum = add(5,6); printf("5+6=%d\n", sum); dlclose(handle); return sum; } 然后编译测试一下,生成 goLoadSo # -ldl 表示调用动态库 gcc -o goLoadSo goLoadSo.c -ldl 执行 goLoadSo ./goLoadSo # 得到结果 a+b=11 5+6=11 go 调用 c 文件 同一个目录,创建 goLoad.go 文件,内容如下,需要注意的是 import "C" 和上面的注释中间不能有空行。 package main /* #cgo LDFLAGS: -ldl #include "./goloadSo.c" int LoadSo(); */ import "C" import "fmt" func main () { fmt.Println(C.LoadSo()) } 然后编译 go build goLoad.go 然后执行 ./goLoad # 输出 a+b=11 5+6=11 11 方式 2-通过第三方包调用 下载包 go get github.com/ebitengine/purego,这个包可以直接调用 so 文件。 package main import ( "fmt" "github.com/ebitengine/purego" ) func main () { libc, err := purego.Dlopen("./add.so", purego.RTLD_LAZY|-purego.RTLD_LOCAL) if err !=nil{ panic(err) } defer purego.Dlclose(libc) // 注册 var add func(int,int)int purego.RegisterLibFunc(&add,libc,"add") fmt.Println(add(2,3)) } 执行代码 go run purego.go # 输出 a+b=5 5
2023年12月24日
186 阅读
0 评论
0 点赞
2023-12-23
go 调用 windows ddl 的 4 种方式
概述 以下举例程序的效果是会弹出消息框。 四种方式 方式 1-立即加载 func LoadDll() { user32Dll, err := syscall.LoadLibrary("user32.dll") if err != nil { panic(err) } // 获取dll里的函数 proc, err := syscall.GetProcAddress(user32Dll, "MessageBoxW") if err != nil { panic(err) } // 宽字节 fromString, err := syscall.UTF16PtrFromString("你好世界") if err != nil { panic(err) } // https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-messageboxw // 参数和返回值,见上面地址 r1, _, _ := syscall.SyscallN(proc, 0, uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型 uintptr(unsafe.Pointer(fromString)), 0, ) if int(r1) == 1 { fmt.Println("用户点击了确定") } } 方式 2-懒加载 func LoadDll2() { u32Dll := syscall.NewLazyDLL("user32.dll") proc := u32Dll.NewProc("MessageBoxW") // 宽字节 fromString, err := syscall.UTF16PtrFromString("你好世界") if err != nil { panic(err) } r1, _, _ := proc.Call( 0, uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型 uintptr(unsafe.Pointer(fromString)), 0, ) if int(r1) == 1 { fmt.Println("用户点击了确定") } r0, _, _ := syscall.SyscallN(proc.Addr(), 0, uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型 uintptr(unsafe.Pointer(fromString)), 0, ) if int(r0) == 1 { fmt.Println("用户点击了确定") } } 方式 3-对第 1 种的封装 func LoadDll3() { u32dll, err := syscall.LoadDLL("user32.dll") if err != nil { panic(err) } proc, err := u32dll.FindProc("MessageBoxW") // 宽字节 fromString, err := syscall.UTF16PtrFromString("你好世界") if err != nil { panic(err) } r1, _, _ := proc.Call( 0, uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型 uintptr(unsafe.Pointer(fromString)), 0, ) if int(r1) == 1 { fmt.Println("用户点击了确定") } r0, _, _ := syscall.SyscallN(proc.Addr(), 0, uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型 uintptr(unsafe.Pointer(fromString)), 0, ) if int(r0) == 1 { fmt.Println("用户点击了确定") } } 方式 4-使用 windows 包 需要安装 go get golang.org/x/sys/windows,实际上是对 NewLazyDLL 的封装,用起来很方便 func LoadDll4() { u32Dll := windows.NewLazySystemDLL("user32.dll") proc := u32Dll.NewProc("MessageBoxW") // 宽字节 fromString, err := syscall.UTF16PtrFromString("你好世界") if err != nil { panic(err) } r1, _, _ := proc.Call( 0, uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型 uintptr(unsafe.Pointer(fromString)), 0, ) if int(r1) == 1 { fmt.Println("用户点击了确定") } r0, _, _ := syscall.SyscallN(proc.Addr(), 0, uintptr(unsafe.Pointer(fromString)), // 因为syscalN适配所有类型的调用,所以统一转这个类型 uintptr(unsafe.Pointer(fromString)), 0, ) if int(r0) == 1 { fmt.Println("用户点击了确定") } }
2023年12月23日
62 阅读
0 评论
0 点赞
2023-12-15
Go-Cache 缓存包 - 高效的Golang 缓存解决方案
第三方包github.com/patrickmn/go-cache 代码实现示例 package cache import ( gocache "github.com/patrickmn/go-cache" "strings" "sync" "time" ) const ( BaseKey = "platform-idstore" ) var ( once sync.Once instance *cache ) var NewCache = New() type Cache interface { Set(k string, v interface{}, d time.Duration) Get(k string) (interface{}, bool) Delete(k string) MatchDelete(matchKey string) Flush() } type cache struct { client gocache.Cache } func (c *cache) addBaseKey(k string) (key string) { return BaseKey + ":" + k } func (c *cache) Set(k string, v interface{}, d time.Duration) { key := c.addBaseKey(k) c.client.Set(key, v, d) } func (c *cache) Get(k string) (interface{}, bool) { key := c.addBaseKey(k) return c.client.Get(key) } func (c *cache) Delete(k string) { key := c.addBaseKey(k) c.client.Delete(key) } func (c *cache) MatchDelete(matchKey string) { keys := c.getMatchKeys(matchKey) for _, key := range keys { c.client.Delete(key) } } func (c *cache) getMatchKeys(match string) (keys []string){ items := c.client.Items() for key, _ := range items { matchKey := c.addBaseKey(match) if strings.Index(key, matchKey) == 0 { keys = append(keys, key) } } return } func (c *cache) Flush() { items := c.client.Items() for key, _ := range items { if strings.Index(key, BaseKey) == 0 { c.Delete(strings.Replace(key, BaseKey + ":", "", 1)) } } } func New() Cache { once.Do(func() { instance = &cache{ client: *gocache.New(1*time.Hour, 6*time.Hour), } }) return instance }
2023年12月15日
109 阅读
1 评论
0 点赞
2023-12-15
Go语言Sort包的深入解析及常见用法
SliceStable 实例讲解 本文章向大家介绍GO SliceStable实例讲解,主要分析其语法、参数、返回值和注意事项,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。 GO语言"sort"包中"SliceStable"函数的用法及代码示例。 用法: func SliceStable(x any, less func(i, j int) bool) SliceStable 使用提供的 less 函数对切片 x 进行排序,保持相等元素的原始顺序。如果 x 不是切片,它会Panics。 less 函数必须满足与接口类型的 Less 方法相同的要求。 例子: package main import ( "fmt" "sort" ) func main() { people := []struct { Name string Age int }{ {"Alice", 25}, {"Elizabeth", 75}, {"Alice", 75}, {"Bob", 75}, {"Alice", 75}, {"Bob", 25}, {"Colin", 25}, {"Elizabeth", 25}, } // Sort by name, preserving original order sort.SliceStable(people, func(i, j int) bool { return people[i].Name < people[j].Name }) fmt.Println("By name:", people) // Sort by age preserving name order sort.SliceStable(people, func(i, j int) bool { return people[i].Age < people[j].Age }) fmt.Println("By age,name:", people) } 输出: By name: [{Alice 25} {Alice 75} {Alice 75} {Bob 75} {Bob 25} {Colin 25} {Elizabeth 75} {Elizabeth 25}] By age,name: [{Alice 25} {Bob 25} {Colin 25} {Elizabeth 25} {Alice 75} {Alice 75} {Bob 75} {Elizabeth 75}]
2023年12月15日
167 阅读
1 评论
0 点赞
2023-12-15
Go 语言网络请求教程和技术指南
post 请求 // 网络客户端 type NetClient interface { Post(url string, req, resp interface{}, header map[string]string) error } func generateUuid() string { u := uuid.NewV4().String() return u } type native struct { c *http.Client } func setHeaders(h http.Header, kv map[string]string) { h.Set("Content-Type", "application/json") h.Set("Access-token", "service") h.Set("Trace-Id", generateUuid()) for key, value := range kv { h.Set(key, value) } } func (n *native) rawPost(url string, data []byte, header map[string]string) (code int, body []byte, err error) { var resp *http.Response reader := bytes.NewReader(data) req, err := http.NewRequest("POST", url, reader) if err != nil { return } // 设置请求头 setHeaders(req.Header, header) resp, err = n.c.Do(req) if resp != nil { defer resp.Body.Close() } if err != nil { return } code = resp.StatusCode body, err = ioutil.ReadAll(resp.Body) return } func (n *native) Post(url string, req, resp interface{}, header map[string]string) (err error) { var reqBytes []byte if reqBytes, err = json.Marshal(req); err != nil { return err } var ( code int body []byte ) if code, body, err = n.rawPost(url, reqBytes, header); err != nil { return err } if code != http.StatusOK { return fmt.Errorf("http response status code !=200,code:%d", code) } return json.Unmarshal(body, resp) }
2023年12月15日
100 阅读
0 评论
0 点赞
2023-12-07
GORM简单使用指南 | Golang ORM 框架
// 删除表 gorm.Migrator().DropTable(dst...) // 自动创建表 db.Migrator().AutoMigrate(dst...) // 转成sql字符串 tx.ToSQL()
2023年12月07日
130 阅读
0 评论
0 点赞
2023-12-04
Go语言Exc包使用指南
输出到文件 cmd := exec.Command( appCfg.MysqlCfg.DumpFilePath, "-h", appCfg.MysqlCfg.Host, "-u", appCfg.MysqlCfg.User, fmt.Sprintf("-p%s", appCfg.MysqlCfg.Password), "-P", appCfg.MysqlCfg.Port, "-B", appCfg.MysqlCfg.Database, ) stdout, err := os.OpenFile("./backup/databases_backup.sql", os.O_CREATE|os.O_WRONLY, 0600) if err != nil { err = fmt.Errorf("创建./backup/databases_backup.sql文件失败,Err%s", err.Error()) return } defer stdout.Close() // 重定向标准输出到文件 cmd.Stdout = stdout // 执行命令 if err = cmd.Start(); err != nil { err = fmt.Errorf("准备执行备份数据库失败,Err%s", err.Error()) return } if err = cmd.Wait(); err != nil { err = fmt.Errorf("执行mysqldump备份数据库失败,Err%s", err.Error()) return } 标准输出 cmd := exec.Command("zip", "-r", "./backup/backup_project.zip", appCfg.ToZipDir) // // 不需要cmd.Run() _, err = cmd.Output() if err != nil { err = fmt.Errorf("执行 zip -r ./backup/backup_project.zip 命令失败,Err%s", err.Error()) return } return
2023年12月04日
137 阅读
0 评论
0 点赞
2023-12-04
Go CloudStore - 云储存集成
国内各大云存储服务接口集成,让云存储使用更方便简单。 GitHub 地址:https://github.com/TruthHun/CloudStore 国内各大云存储服务接口集成,让云存储使用更方便简单。 目前集成的有:阿里云OSS, 百度云BOS、腾讯云COS、华为云OBS、七牛云、又拍云、Minio
2023年12月04日
125 阅读
0 评论
0 点赞
2023-11-28
深度解析Golang的Lo包,進一步掌握Golang
概述 开发中,我们经常遇到一些操作,比如获取一个 map 的所有 key,所有 value,判断一个字符串是否出现在 slice 中,slice 中是否有重复元素等等。在 Python 中是直接支持的:d.keys()、d.values()、str in strList、l.count(str)。Go 语言没有这样的操作,标准库也不提供。因此我们自己,或者团队会维护一些这类操作的包。 得益于 Go 泛型的发布,lo 就是这样的包,封装了大量简单操作,可以降低我们的代码量。 https://github.com/samber/lo 除了 lo,Go 官方也提供了一些实验性的包,比如 golang.org/x/exp/map、golang.org/x/exp/slices。这些包针对特定的数据结构,更小,引入项目时更灵活,并且可能成为标准库的一部分。而 lo 则更全面。 下面主要介绍 lo。 slice helpers Filter 这个函数实现了 Python 中的 filter 函数:迭代一个 slice,计算每个元素,如果匿名函数返回 false,则被过滤掉。 even := lo.Filter[int]([]int{1, 2, 3, 4}, func(x int, _ int) bool { return x%2 == 0 }) // []int{2, 4} Map 这个函数将 slice 中每个元素映射成另一个元素,新元素的类型不一定和源元素的相同。 lo.Map[int64, string]([]int64{1, 2, 3, 4}, func(x int64, _ int) string { return strconv.FormatInt(x, 10) }) // []string{"1", "2", "3", "4"} FilterMap 这个函数对 slice 同时执行 filter 和 map。分别调用 filter 和 map 也能实现这个功能,为什么还要实现 FilterMap 呢?原因也很简单,FilterMap 可以减少一个循环。 m := []string{"cpu", "gpu", "mouse", "keyboard"} matching := lo.FilterMap[string, string](m, func(x string, _ int) (string, bool) { if strings.HasSuffix(x, "pu") { return "xpu", true } return "", false }) // []string{"xpu", "xpu"} FlatMap 这个函数将 slice 中每个元素转换成另一个 slice,最后合并成一个 slice。 lo.FlatMap[int, string]([]int{0, 1, 2}, func(x int, _ int) []string { return []string{ strconv.FormatInt(x, 10), strconv.FormatInt(x, 10), } }) // []string{"0", "0", "1", "1", "2", "2"} Reduce 这个函数和 Python 中的 reduce 一样。将一个 slice 经过计算,变成一个标量值。 sum := lo.Reduce[int, int]([]int{1, 2, 3, 4}, func(agg int, item int, _ int) int { return agg + item }, 0) // 10 ReduceRight 和 reduce 一样,只不过从右向左迭代: v := [][]int{{0, 1}, {2, 3}, {4, 5}} result := lo.ReduceRight[[]int, []int](v, func(agg []int, item []int, _ int) []int { return append(agg, item...) }, []int{})) // []int{4, 5, 2, 3, 0, 1} ForEach lo.ForEach[string]([]string{"hello", "world"}, func(x string, _ int) { println(x) }) // prints "hello\nworld\n" 此函数也有并行版本。每个元素在 goroutine 中执行。 import lop "github.com/samber/lo/parallel" lop.ForEach[string]([]string{"hello", "world"}, func(x string, _ int) { println(x) }) // prints "hello\nworld\n" or "world\nhello\n" Times 调用指定函数 n 次,将每次的返回值合并成一个 slice。 import "github.com/samber/lo" lo.Times[string](3, func(i int) string { return strconv.FormatInt(int64(i), 10) }) // []string{"0", "1", "2"} 此函数也有一个并行版本: import lop "github.com/samber/lo/parallel" lop.Times[string](3, func(i int) string { return strconv.FormatInt(int64(i), 10) }) // []string{"0", "1", "2"} Uniq 去重。 uniqValues := lo.Uniq[int]([]int{1, 2, 2, 1}) // []int{1, 2} UniqBy 去重的同时,对元素执行一些计算。 uniqValues := lo.UniqBy[int, int]([]int{0, 1, 2, 3, 4, 5}, func(i int) int { return i%3 }) // []int{0, 1, 2} GroupBy[并行] 对 slice 元素分组,返回一个 map,key 是分组,value 是属于这个分组的元素。 import lo "github.com/samber/lo" groups := lo.GroupBy[int, int]([]int{0, 1, 2, 3, 4, 5}, func(i int) int { return i%3 }) // map[int][]int{0: []int{0, 3}, 1: []int{1, 4}, 2: []int{2, 5}} 支持并行: import lop "github.com/samber/lo/parallel" lop.GroupBy[int, int]([]int{0, 1, 2, 3, 4, 5}, func(i int) int { return i%3 }) // map[int][]int{0: []int{0, 3}, 1: []int{1, 4}, 2: []int{2, 5}} Chunk 将 slice 分块。 lo. Chunk[int]([]int{0, 1, 2, 3, 4, 5}, 2) // [][]int {{0, 1}, {2, 3}, {4, 5}} lo. Chunk[int]([]int{0, 1, 2, 3, 4, 5, 6}, 2) // [][]int {{0, 1}, {2, 3}, {4, 5}, {6}} lo. Chunk[int]([]int{}, 2) // [][]int{} lo. Chunk[int]([]int{0}, 2) // [][]int {{0}} PartitionBy[并行] 和 groupBy 非常像,但返回 slice。 import lo "github. com/samber/lo" partitions := lo. PartitionBy[int, string]([]int{-2, -1, 0, 1, 2, 3, 4, 5}, func (x int) string { if x < 0 { return "negative" } else if x%2 == 0 { return "even" } return "odd" }) // [][]int {{-2, -1}, {0, 2, 4}, {1, 3, 5}} Flatten 将多层级的 slice 变成一层 slice。 flat := lo. Flatten[int]([][]int {{0, 1}, {2, 3, 4, 5}} ) // []int{0, 1, 2, 3, 4, 5} Shuffle 使用 Fisher-Yates 算法洗牌。 randomOrder := lo. Shuffle[int]([]int{0, 1, 2, 3, 4, 5}) // []int{1, 4, 0, 3, 5, 2} Reverse 反转顺序 reverseOrder := lo. Reverse[int]([]int{0, 1, 2, 3, 4, 5}) // []int{5, 4, 3, 2, 1, 0} Fill 使用初始值对元素初始化。 type foo struct { bar string } func (f foo) Clone () foo { return foo{f.bar} } initializedSlice := lo.Fill[foo]([]foo{foo{"a"}, foo{"a"}}, foo{"b"}) // []foo{foo{"b"}, foo{"b"}} Repeat 和 Python 中的 repeat 一样。 type foo struct { bar string } func (f foo) Clone () foo { return foo{f.bar} } slice := lo. Repeat[foo](2, foo{"a"}) // []foo{foo{"a"}, foo{"a"}} RepeatBy 产生一个 slice,传入回调函数当前次数。 slice := lo. RepeatBy[string](0, func (i int) string { return strconv.FormatInt (math.Pow (i, 2), 10) }) // []int{} slice := lo. RepeatBy[string](5, func (i int) string { return strconv.FormatInt (math.Pow (i, 2), 10) }) // []int{0, 1, 4, 9, 16} KeyBy 对 slice 中的每个元素,计算出对应的 key,最后返回一个 map。 m := lo. KeyBy[int, string]([]string{"a", "aa", "aaa"}, func (str string) int { return len (str) }) // map[int]string{1: "a", 2: "aa", 3: "aaa"} type Character struct { dir string code int } characters := []Character{ {dir: "left", code: 97}, {dir: "right", code: 100}, } result := lo. KeyBy[string, Character](characters, func (char Character) string { return string (rune (char. code)) }) //map[a:{dir: left code: 97} d:{dir: right code: 100}] Associate (alias: SliceToMap) 返回一个 map,其中的 key/value 对由回调函数给出,slice 中每个元素都会变成 map 中的一个 key/value 对。 in := []*foo {{baz: "apple", bar: 1}, {baz: "banana", bar: 2}} , aMap := lo. Associate[*foo, string, int](in, func (f *foo) (string, int) { return f.baz, f.bar }) // map[string][int]{ "apple": 1, "banana": 2 } Drop 丢掉前 n 个元素。 l := lo. Drop[int]([]int{0, 1, 2, 3, 4, 5}, 2) // []int{2, 3, 4, 5} DropRight 丢掉后 n 个元素。 l := lo. DropRight[int]([]int{0, 1, 2, 3, 4, 5}, 2) // []int{0, 1, 2, 3} DropWhile 从前往后,丢掉不符合回调函数要求的元素,直到某个元素不满足要求时停止,返回剩下的元素。剩下的元素不论满足不满足回调函数,都会返回。 l := lo. DropWhile[string]([]string{"a", "aa", "aaa", "aa", "aa"}, func (val string) bool { return len (val) <= 2 }) // []string{"aaa", "aa", "aa"} DropRightWhile 和 DropWhile 类似,从后往前计算,丢掉后面几个满足要求的元素,直到某个元素不满足要求时停止,返回剩下的元素。剩下的元素不论满足不满足回调函数,都会返回。 l := lo. DropRightWhile[string]([]string{"a", "aa", "aaa", "aa", "aa"}, func (val string) bool { return len (val) <= 2 }) // []string{"a", "aa", "aaa"} Reject 是 Filter 的反操作,拒绝掉会覅函数返回 true 的元素,返回剩下的元素。 odd := lo. Reject[int]([]int{1, 2, 3, 4}, func (x int, _ int) bool { return x%2 == 0 }) // []int{1, 3} Count 和 python 的 list.count (x) 一样,返回某个元素出现的次数。 count := lo. Count[int]([]int{1, 5, 1}, 1) // 2 CountBy 计算符合回调函数的元素的个数。 count := lo. CountBy[int]([]int{1, 5, 1}, func (i int) bool { return i < 4 }) // 2 Subset 实现了 slice[start:start+length]。但越界时不会 panic。 in := []int{0, 1, 2, 3, 4} sub := lo.Subset (in, 2, 3) // []int{2, 3, 4} sub := lo.Subset (in, -4, 3) // []int{1, 2, 3} sub := lo.Subset (in, -2, math. MaxUint) // []int{3, 4} Slice 实现了 slice[start: end]。但越界时不会 panic。 in := []int{0, 1, 2, 3, 4} slice := lo.Slice (in, 0, 5) // []int{0, 1, 2, 3, 4} slice := lo.Slice (in, 2, 3) // []int{2} slice := lo.Slice (in, 2, 6) // []int{2, 3, 4} slice := lo.Slice (in, 4, 3) // []int{} Replace 替换 slice 中的元素,可以指定原始值,替换后的值,以及替换次数。 in := []int{0, 1, 0, 1, 2, 3, 0} slice := lo.Replace (in, 0, 42, 1) // []int{42, 1, 0, 1, 2, 3, 0} slice := lo.Replace (in, -1, 42, 1) // []int{0, 1, 0, 1, 2, 3, 0} slice := lo.Replace (in, 0, 42, 2) // []int{42, 1, 42, 1, 2, 3, 0} slice := lo.Replace (in, 0, 42, -1) // []int{42, 1, 42, 1, 2, 3, 42} ReplaceAll 和 Replace 一样,但不能指定替换次数。 in := []int{0, 1, 0, 1, 2, 3, 0} slice := lo.ReplaceAll (in, 0, 42) // []int{42, 1, 42, 1, 2, 3, 42} slice := lo.ReplaceAll (in, -1, 42) // []int{0, 1, 0, 1, 2, 3, 0} Compact 去除零值元素。 in := []string{"", "foo", "", "bar", ""} slice := lo. Compact [string](in) // []string{"foo", "bar"} IsSorted 判断 slcie 是否有序 slice := lo.IsSorted ([]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) // true IsSortedByKey 判断 slice 是否关于某个 key 有序,回调函数计算每个元素的 key。 slice := lo.IsSortedByKey ([]string{"a", "bb", "ccc"}, func (s string) int { return len (s) }) // true map helpers Keys 返回 map 的所有 key。 keys := lo. Keys[string, int](map[string]int{"foo": 1, "bar": 2}) // []string{"bar", "foo"} Values 返回 map 的所有 value。 values := lo. Values[string, int](map[string]int{"foo": 1, "bar": 2}) // []int{1, 2} PickBy 类似于 slice 的 filter。只返回一个 map 中符合条件的 key/value 对。 m := lo. PickBy[string, int](map[string]int{"foo": 1, "bar": 2, "baz": 3}, func (key string, value int) bool { return value%2 == 1 }) // map[string]int{"foo": 1, "baz": 3} PickByKeys 只返回给定 key 的 map。 m := lo. PickByKeys[string, int](map[string]int{"foo": 1, "bar": 2, "baz": 3}, []string{"foo", "baz"}) // map[string]int{"foo": 1, "baz": 3} PickByValues 只返回给定值的 map m := lo. PickByValues[string, int](map[string]int{"foo": 1, "bar": 2, "baz": 3}, []int{1, 3}) // map[string]int{"foo": 1, "baz": 3} OmitBy 忽略掉符合条件的,返回剩下的 map m := lo. OmitBy[string, int](map[string]int{"foo": 1, "bar": 2, "baz": 3}, func (key string, value int) bool { return value%2 == 1 }) // map[string]int{"bar": 2} OmitByKeys 忽略掉给定 key,剩下的 key 组成新 map m := lo. OmitByKeys[string, int](map[string]int{"foo": 1, "bar": 2, "baz": 3}, []string{"foo", "baz"}) // map[string]int{"bar": 2} OmitByValues 忽略掉给定 value,剩下的组成新 map m := lo. OmitByValues[string, int](map[string]int{"foo": 1, "bar": 2, "baz": 3}, []int{1, 3}) // map[string]int{"bar": 2} Entries (alias: ToPairs) 将 map 变成 key/value 对。 entries := lo. Entries[string, int](map[string]int{"foo": 1, "bar": 2}) // []lo. Entry[string, int]{ // { // Key: "foo", // Value: 1, // }, // { // Key: "bar", // Value: 2, // }, // } FromEntries (alias: FromPairs) 将 key/value 对编程 map m := lo. FromEntries[string, int]([]lo. Entry[string, int]{ { Key: "foo", Value: 1, }, { Key: "bar", Value: 2, }, }) // map[string]int{"foo": 1, "bar": 2} Invert key 变 value,value 变 key。可能因为重复的 value 而丢失数据。 m 1 := lo. Invert[string, int]([map[string]int{"a": 1, "b": 2}) // map[int]string{1: "a", 2: "b"} m 2 := lo. Invert[string, int]([map[string]int{"a": 1, "b": 2, "c": 1}) // map[int]string{1: "c", 2: "b"} Assign 从左到右,逐个合并 map,返回新 map。 mergedMaps := lo. Assign[string, int]( map[string]int{"a": 1, "b": 2}, map[string]int{"b": 3, "c": 4}, ) // map[string]int{"a": 1, "b": 3, "c": 4} MapKeys 将 map 的 key 转成另一个值。 m 2 := lo. MapKeys[int, int, string](map[int]int{1: 1, 2: 2, 3: 3, 4: 4}, func (_ int, v int) string { return strconv.FormatInt (int 64 (v), 10) }) // map[string]int{"1": 1, "2": 2, "3": 3, "4": 4} MapValues 将 map 的 value 转成另一个值。 m 1 := map[int]int 64{1: 1, 2: 2, 3: 3} m 2 := lo. MapValues[int, int 64, string](m 1, func (x int 64, _ int) string { return strconv.FormatInt (x, 10) }) // map[int]string{1: "1", 2: "2", 3: "3"} MapToSlice 将 key/value 对转成一个值,放入 slice。 m := map[int]int 64{1: 4, 2: 5, 3: 6} s := lo.MapToSlice (m, func (k int, v int 64) string { return fmt.Sprintf ("%d_%d", k, v) }) // []string{"1_4", "2_5", "3_6"} math helpers 这三个函数就是 Python 中的 range。 Range result := Range (4) // [0, 1, 2, 3] result := Range (-4); // [0, -1, -2, -3] result := Range (0); // [] RangeFrom result := RangeFrom (1, 5); // [1, 2, 3, 4] result := RangeFrom[float 64](1.0, 5); // [1.0, 2.0, 3.0, 4.0] RangeWithSteps result := RangeWithSteps (0, 20, 5); // [0, 5, 10, 15] result := RangeWithSteps[float 32](-1.0, -4.0, -1.0); // [-1.0, -2.0, -3.0] result := RangeWithSteps (1, 4, -1); // [] Clamp 这个函数怎么用? r 1 := lo.Clamp (0, -10, 10) // 0 r 2 := lo.Clamp (-42, -10, 10) // -10 r 3 := lo.Clamp (42, -10, 10) // 10 SumBy 求和 strings := []string{"foo", "bar"} sum := lo.SumBy (strings, func (item string) int { return len (item) }) // 6 string helpers Substring sub := lo.Substring ("hello", 2, 3) // "llo" sub := lo.Substring ("hello", -4, 3) // "ell" sub := lo.Substring ("hello", -2, math. MaxUint) // "lo" ChunkString 分块 lo.ChunkString ("123456", 2) // []string{"12", "34", "56"} lo.ChunkString ("1234567", 2) // []string{"12", "34", "56", "7"} lo.ChunkString ("", 2) // []string{""} lo.ChunkString ("1", 2) // []string{"1"} RuneLength sub := lo.RuneLength ("hellô") // 5 sub := len ("hellô") // 6 RandomString 随机字符串 lo.RandomString(6, lo.NumbersCharset) tuple helpers T 2 -> T 9 不懂 tuple 1 := lo. T 2[string, int]("x", 1) // Tuple 2[string, int]{A: "x", B: 1} func example () (string, int) { return "y", 2 } tuple 2 := lo. T 2[string, int](example ()) // Tuple 2[string, int]{A: "y", B: 2} Unpack 2 -> Unpack 9 不懂 + 1 r 1, r 2 := lo. Unpack 2[string, int](lo. Tuple 2[string, int]{"a", 1}) // "a", 1 Zip 2 -> Zip 9 不懂 + 2 tuples := lo. Zip 2[string, int]([]string{"a", "b"}, []int{1, 2}) // []Tuple 2[string, int] {{A: "a", B: 1}, {A: "b", B: 2}} Unzip 2 -> Unzip 9 不懂 + 3 a, b := lo. Unzip 2[string, int]([]Tuple 2[string, int] {{A: "a", B: 1}, {A: "b", B: 2}} ) // []string{"a", "b"} // []int{1, 2} channel helpers ChannelDispatcher 将一个 channel 扩展出多个二级 channel,然后多个 consumer 消费二级 channel。没想到这功能都被作者整进来了。 ch := make (chan int, 42) for i := 0; i <= 10; i++ { ch <- i } children := lo.ChannelDispatcher (ch, 5, 10, DispatchingStrategyRoundRobin[int]) // []<-chan int{...} consumer := func (c <-chan int) { for { msg, ok := <-c if !ok { println ("closed") break } println (msg) } } for i := range children { go consumer (children[i]) } intersection helpers Contains present := lo. Contains[int]([]int{0, 1, 2, 3, 4, 5}, 5) // true ContainsBy 集合中包含符合某种条件的元素。 present := lo. ContainsBy[int]([]int{0, 1, 2, 3, 4, 5}, func (x int) bool { return x == 3 }) // true Every 两个集合是否是包含关系。 这名字。。。。 ok := lo. Every[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}) // true ok := lo. Every[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 6}) // false EveryBy 集合元素是否都符合某种条件。 b := EveryBy[int]([]int{1, 2, 3, 4}, func (x int) bool { return x < 5 }) // true Some 两个集合有交集就行。。。 ok := lo. Some[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}) // true ok := lo. Some[int]([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6}) // false SomeBy 集合有任意元素满足条件就行。。。 b := SomeBy[int]([]int{1, 2, 3, 4}, func (x int) bool { return x < 3 }) // true None 两个集合没有交集 b := None[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}) // false b := None[int]([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6}) // true NoneBy 没有符合条件的元素就行。。。 b := NoneBy[int]([]int{1, 2, 3, 4}, func (x int) bool { return x < 0 }) // true Intersect 返回两个集合的交集 result 1 := lo. Intersect[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2}) // []int{0, 2} result 2 := lo. Intersect[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 6} // []int{0} result 3 := lo. Intersect[int]([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6}) // []int{} Difference 会返回差集。left 为 A - B,right 为 B - A left, right := lo. Difference[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 6}) // []int{1, 3, 4, 5}, []int{6} left, right := lo. Difference[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3, 4, 5}) // []int{}, []int{} Union 并集 union := lo. Union[int]([]int{0, 1, 2, 3, 4, 5}, []int{0, 2, 10}) // []int{0, 1, 2, 3, 4, 5, 10} Without 叫 Remove 更合适 subset := lo. Without[int]([]int{0, 2, 10}, 2) // []int{0, 10} subset := lo. Without[int]([]int{0, 2, 10}, 0, 1, 2, 3, 4, 5) // []int{10} WithoutEmpty 移除 0 值 subset := lo. WithoutEmpty[int]([]int{0, 2, 10}) // []int{2, 10} search helpers IndexOf found := lo. IndexOf[int]([]int{0, 1, 2, 1, 2, 3}, 2) // 2 notFound := lo. IndexOf[int]([]int{0, 1, 2, 1, 2, 3}, 6) // -1 LastIndexOf found := lo. LastIndexOf[int]([]int{0, 1, 2, 1, 2, 3}, 2) // 4 notFound := lo. LastIndexOf[int]([]int{0, 1, 2, 1, 2, 3}, 6) // -1 conditional helpers type manipulation helpers function helpers Partial 偏函数,像 Python 那样。 add := func (x, y int) int { return x + y } f := lo.Partial (add, 5) f (10) // 15 f (42) // 47 concurrency helpers error handling 不建议使用。 这篇文章还在更新中。在看这些函数的时候,我又想起了 Python 中那些简单又易读的实现方式了。如果有一天 Go 也支持操作符重载就好。 这些函数是那么丑陋。。。
2023年11月28日
158 阅读
0 评论
0 点赞
2023-11-28
Go Excelize 最全面的Excel解析包使用指南
// 打开excel文件 excelize.OpenReader(excelFile) // 初始化一个空excel excelize.NewFile() // 获取excel的sheet名称 excelObj.GetSheetList() // excel文件对象类型 excelObj *excelize.File // 新建一个sheet excelObj.NewSheet(sheet) // 删除一个sheet excelObj.DeleteSheet(sheet) // 获取某个sheet的行 rows, err := excelObj.GetRows(sheet) // 遍历所有单元格,将一个excel内容,copy到另外一个excel文件里(是不是有更加简单的方式,直接将sheet添加过去) for iR, row := range rows { for iC, cell := range row { // 行列坐标,例如A1,A2.... axis, err := excelize.CoordinatesToCellName(iC+1, iR+1) // 单元格类型,excelize.CellTypeUnset类型,不懂要不是做些特殊处理 cellType, err := fromFile.GetCellType(sheet, axis) // 坐标设置值 err = toFile.SetCellValue(sheet, axis, cell) // 列的数字转名称,例如1是A,2是B colName, err := excelize.ColumnNumberToName(iC + 1) // 获取excel文件对应sheet的,对于列的列宽度 width, err := fromFile.GetColWidth(sheet, colName) // 设置列的宽度为模板的宽度 _ = toFile.SetColWidth(sheet, colName, colName, width) } // 设置行的高度 height, err := fromFile.GetRowHeight(sheet, iR+1) _ = toFile.SetRowHeight(sheet, iR+1, height) }
2023年11月28日
134 阅读
0 评论
0 点赞
1
2
3
...
7