All skills
gogf avatar

/goframe-v2

@911705d
by GoFramegogf/skills81 stars
3

GoFrame v2 development skill. Use only when the target Go project uses or is explicitly adopting GoFrame v2: the nearest go.mod requires github.com/gogf/gf/v2, existing Go files import github.com/gogf/gf/v2 or any github.com/gogf/gf/v2/... component package, or the user asks to scaffold, migrate, or build with GoFrame. Trigger for GoFrame-backed Go work such as APIs/controllers/services, middleware, routing/config, ORM/DAO/DO/entity/database operations, gf CLI/codegen, HTTP/gRPC services, and microservice conventions. Do not trigger for generic Go projects without GoFrame evidence, frontend-only work, shell scripts, or unrelated infrastructure tasks.

Use this Skill: https://skilld.dev/gh/gogf/skills/goframe-v2

This session only. Nothing lands on disk.

references组件列表数据结构集合类型-gset集合类型-基本使用.md

泛型集合(推荐使用)

从 v2.10 版本开始,gset 提供了泛型集合 TSet[T],提供类型安全的集合操作。

基本使用

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/container/gset"
)

func main() {
    // 创建一个string类型的泛型集合
    s := gset.NewTSet[string]()
    
    // 添加元素
    s.Add("apple")
    s.Add("banana")
    s.Add("orange")
    s.Add("apple") // 重复元素不会被添加
    
    // 获取集合大小
    fmt.Println("Size:", s.Size()) // 输出: Size: 3
    
    // 检查元素是否存在
    fmt.Println("Contains apple:", s.Contains("apple")) // 输出: Contains apple: true
    
    // 获取所有元素
    fmt.Println("Elements:", s.Slice())
    
    // 遍历集合
    s.Iterator(func(v string) bool {
        fmt.Println("Element:", v)
        return true
    })
}

集合运算

泛型集合支持交集、并集、差集、补集等运算。

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/container/gset"
)

func main() {
    s1 := gset.NewTSetFrom[int]([]int{1, 2, 3, 4, 5})
    s2 := gset.NewTSetFrom[int]([]int{4, 5, 6, 7, 8})
    
    // 交集
    fmt.Println("Intersect:", s1.Intersect(s2).Slice()) // [4 5]
    
    // 并集
    fmt.Println("Union:", s1.Union(s2).Slice()) // [1 2 3 4 5 6 7 8]
    
    // 差集
    fmt.Println("Diff:", s1.Diff(s2).Slice()) // [1 2 3]
    
    // 补集
    full := gset.NewTSetFrom[int]([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
    fmt.Println("Complement:", s1.Complement(full).Slice()) // [6 7 8 9 10]
}

自定义 nil 值检查器

对于指针类型或接口类型,可以使用自定义 nil 检查器。

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/container/gset"
)

type User struct {
    ID   int
    Name string
}

func main() {
    // 创建带自定义nil检查器的集合
    s := gset.NewTSetWithChecker[*User](func(u *User) bool {
        return u == nil || u.ID == 0
    })
    
    s.Add(&User{ID: 1, Name: "John"})
    s.Add(&User{ID: 2, Name: "Jane"})
    s.Add(&User{ID: 0, Name: "Invalid"}) // 会被视为nil,不会添加
    
    fmt.Println("Size:", s.Size()) // 输出: Size: 2
}

泛型集合特点

  1. 类型安全:在编译期就能发现类型错误,避免运行时类型断言失败。
  2. 自定义 nil 检查(可选):通过 NewTSetWithChecker 函数,可以为泛型类型自定义 nil 判断逻辑,解决 typed nil 问题。默认情况下使用反射判断。
  3. 性能优势:减少了类型断言和反射的开销。
  4. 更好的IDE支持:IDE能够提供更准确的代码补全和类型提示。

:::tip 推荐在新项目中使用泛型集合 TSet[T],它提供了更好的类型安全性和开发体验。 :::

传统集合类型

下面介绍传统的集合类型,这些类型在旧版本中被广泛使用,仍然完全支持。

基本使用

package main

import (
    "github.com/gogf/gf/v2/container/gset"
    "fmt"
)

func main() {
    // 创建一个并发安全的集合对象
    s := gset.New(true)

    // 添加数据项
    s.Add(1)

    // 批量添加数据项
    s.Add([]interface{}{1, 2, 3}...)

    // 集合数据项大小
    fmt.Println(s.Size())

    // 集合中是否存在指定数据项
    fmt.Println(s.Contains(2))

    // 返回数据项slice
    fmt.Println(s.Slice())

    // 删除数据项
    s.Remove(3)

    // 遍历数据项
    s.Iterator(func(v interface{}) bool {
        fmt.Println("Iterator:", v)
        return true
    })

    // 将集合转换为字符串
    fmt.Println(s.String())

    // 并发安全写锁操作
    s.LockFunc(func(m map[interface{}]struct{}) {
        m[4] = struct{}{}
    })

    // 并发安全读锁操作
    s.RLockFunc(func(m map[interface{}]struct{}) {
        fmt.Println(m)
    })

    // 清空集合
    s.Clear()
    fmt.Println(s.Size())
}

执行后,输出结果为:

true
[1 2 3]
Iterator: 1
Iterator: 2
[1 2]
map[1:{} 2:{} 4:{}]
0

交差并补集

我们可以使用以下方法实现交差并补集,并返回一个新的结果集合,

func (set *Set) Intersect(others ...*Set) (newSet *Set)
func (set *Set) Diff(others ...*Set) (newSet *Set)
func (set *Set) Union(others ...*Set) (newSet *Set)
func (set *Set) Complement(full *Set) (newSet *Set)
  1. Intersect: 交集,属于set且属于others的元素为元素的集合。
  2. Diff: 差集,属于set且不属于others的元素为元素的集合。
  3. Union: 并集,属于set或属于others的元素为元素的集合。
  4. Complement: 补集,(前提: set应当为full的子集)属于全集full不属于集合set的元素组成的集合。如果给定的full集合不是set的全集时,返回full与set的差集.

通过集合方法我们可以发现,交差并集方法支持多个集合参数进行计算。以下为简化示例,只使用一个参数集合。

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/frame/g"
    "github.com/gogf/gf/v2/container/gset"
)

func main() {
    s1 := gset.NewFrom(g.Slice{1, 2, 3})
    s2 := gset.NewFrom(g.Slice{4, 5, 6})
    s3 := gset.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7})

    // 交集
    fmt.Println(s3.Intersect(s1).Slice())
    // 差集
    fmt.Println(s3.Diff(s1).Slice())
    // 并集
    fmt.Println(s1.Union(s2).Slice())
    // 补集
    fmt.Println(s1.Complement(s3).Slice())
}

执行后,输出结果为:

[1 2 3]
[4 5 6 7]
[1 2 3 4 5 6]
[7 4 5 6]

Contains/ContainsI 包含判断

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/container/gset"
)

func main() {
    var set gset.StrSet
    set.Add("a")
    fmt.Println(set.Contains("a"))
    fmt.Println(set.Contains("A"))
    fmt.Println(set.ContainsI("A"))

    // Output:
    // true
    // false
    // true
}

Pop/Pops 集合项出栈

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/container/gset"
)

func main() {
    var set gset.Set
    set.Add(1, 2, 3, 4)
    fmt.Println(set.Pop())
    fmt.Println(set.Pops(2))
    fmt.Println(set.Size())

    // May Output:
    // 1
    // [2 3]
    // 1
}

Join 集合项串连

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/container/gset"
)

func main() {
    var set gset.Set
    set.Add("a", "b", "c", "d")
    fmt.Println(set.Join(","))

    // May Output:
    // a,b,c,d
}

IsSubsetOf 子集判断

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/container/gset"
    "github.com/gogf/gf/v2/frame/g"
)

func main() {
    var s1, s2 gset.Set
    s1.Add(g.Slice{1, 2, 3}...)
    s2.Add(g.Slice{2, 3}...)
    fmt.Println(s1.IsSubsetOf(&s2))
    fmt.Println(s2.IsSubsetOf(&s1))

    // Output:
    // false
    // true
}

AddIfNotExist* 判断性写入

判断性写入是指当指定的数据项不存在时则写入并且方法返回 true,否则忽略吸入并且方法返回 false。相关方法如下:

  • AddIfNotExist
  • AddIfNotExistFunc
  • AddIfNotExistFuncLock

方法具体描述请查看接口文档或源码注释。

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/container/gset"
)

func main() {
    var set gset.Set
    fmt.Println(set.AddIfNotExist(1))
    fmt.Println(set.AddIfNotExist(1))
    fmt.Println(set.Slice())

    // Output:
    // true
    // false
    // [1]
}

Walk 遍历修改

package main

import (
    "fmt"
    "github.com/gogf/gf/v2/container/gset"
    "github.com/gogf/gf/v2/frame/g"
)

func main() {
    var (
        set    gset.StrSet
        names  = g.SliceStr{"user", "user_detail"}
        prefix = "gf_"
    )
    set.Add(names...)
    // Add prefix for given table names.
    set.Walk(func(item string) string {
        return prefix + item
    })
    fmt.Println(set.Slice())

    // May Output:
    // [gf_user gf_user_detail]
}

JSON 序列化/反序列

gset 模块下的所有容器类型均实现了标准库 json 数据格式的序列化/反序列化接口。

  1. Marshal
package main

import (
       "encoding/json"
       "fmt"
       "github.com/gogf/gf/v2/container/gset"
)

func main() {
       type Student struct {
           Id     int
           Name   string
           Scores *gset.IntSet
       }
       s := Student{
           Id:     1,
           Name:   "john",
           Scores: gset.NewIntSetFrom([]int{100, 99, 98}),
       }
       b, _ := json.Marshal(s)
       fmt.Println(string(b))
}

执行后,终端输出:

{"Id":1,"Name":"john","Scores":[100,99,98]}
  1. Unmarshal
package main

import (
       "encoding/json"
       "fmt"
       "github.com/gogf/gf/v2/container/gset"
)

func main() {
       b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
       type Student struct {
           Id     int
           Name   string
           Scores *gset.IntSet
       }
       s := Student{}
       json.Unmarshal(b, &s)
       fmt.Println(s)
}

执行后,输出结果:

{1 john [100,99,98]}

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk MEDIUM
  • Gen Agent Trust Hub16d

    The skill provides a comprehensive development guide and code examples for the GoFrame v2 framework. While highly informative for Go developers, it contains several examples with hardcoded placeholder secrets, tokens, and specific local file paths to sensitive configuration files (like Kubernetes credentials). These elements are provided for demonstration purposes but represent insecure practices if used in production without modification.

  • Socket16d

    5 alerts: gptSecurity, gptAnomaly

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    227/949 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 911705d. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 4 months ago.

Steadyupdated 4 months ago
  • Go
  • Database
  • goframe
  • orm
  • http
  • grpc
  • microservices
  • crud
  • scaffolding
  • middleware

README badge

README badge for gogf/skills

Provides instruction and conventions for developing with GoFrame v2, a modular Go framework for building HTTP and gRPC services, microservices, and database operations using its ORM, CLI tooling, and project scaffolding. Use this skill when the target project has GoFrame v2 as a dependency or when the user requests scaffolding, migrations, or service development with GoFrame conventions.

Generated from the current SKILL.md.

When should I use this skill?
Use this skill only when your Go project uses GoFrame v2, indicated by github.com/gogf/gf/v2 in go.mod or imports. Do not use for generic Go projects, frontend work, or infrastructure tasks unrelated to GoFrame.
Should I manually set created_at and updated_at fields?
No. GoFrame automatically writes created_at on insert and updated_at on insert/update/save. Manually setting these fields is redundant and violates project conventions.
What should I use for database operations instead of g.Map?
Always use DO objects from internal/model/do/. DO struct fields are interface{}, unset fields remain nil and are automatically ignored by the ORM.
How does soft delete work in GoFrame?
Call Delete() on the DAO; GoFrame automatically converts it to UPDATE SET deleted_at = NOW(). Queries automatically filter out soft-deleted rows without requiring manual WhereNull conditions.
Where should I implement business logic?
Implement business logic directly in the service/ directory. Do not use the logic/ directory unless explicitly requested.

Generated from the current SKILL.md. These answers refresh after source changes.