golang实现泛型元组数据结构的插件库go-tuple的使用

Golang实现泛型元组数据结构的插件库go-tuple的使用

go-tuple是一个为Go 1.18+设计的泛型元组实现库,允许你存储1到9个不同类型的值而不需要自定义结构体。

基本用法

// 创建一个包含2个元素的元组
tup := tuple.New2(5, "hi!")
fmt.Println(tup.V1) // 输出: 5
fmt.Println(tup.V2) // 输出: "hi!"

// 创建一个更长的元组
longerTuple := tuple.New5("this", "is", "one", "long", "tuple")

元组在不同场景中的应用

元组可以用作切片或数组项、映射键或值,以及通道负载:

// 映射中保存元组
tupInMap := make(map[tuple.T2[string, string]]Person)
tupInMap[tuple.New2("John", "Doe")] = Person{
    FirstName: "John",
    LastName: "Doe",
    // ...
}

// 通道中保存元组
tupInChan := make(chan tuple.T2[string, error])
go func() {
    defer close(tupInChan)
    tupInChan <- tuple.New2(os.Getwd())
}()
fmt.Print(<-tupInChan)

从函数调用创建元组

func vals() (int, string) {
    return 5, "hi!"
}

func main() {
    tup := tuple.New2(vals())
    fmt.Println(tup.V1)
    fmt.Println(tup.V2)
}

将元组作为函数参数传递

func main() {
    tup := tuple.New2(5, "hi!")
    printValues(tup.Values())
}

func printValues(a int, b string) {
    fmt.Println(a)
    fmt.Println(b)
}

访问元组值

tup := tuple.New2(5, "hi!")
a, b := tup.Values()

JSON编组

元组会被编组和解组为JSON数组:

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age,omitempty"`
}

type MyJSON struct {
    Users []tuple.T2[string, User] `json:"users"`
}

func main() {
    data := MyJSON{
        Users: []tuple.T2[string, User]{
            tuple.New2("foo", User{Name: "foo", Age: 42}),
            tuple.New2("bar", User{Name: "bar", Age: 21}),
            tuple.New2("baz", User{Name: "baz"}),
        },
    }

    marshalled, _ := json.Marshal(data)
    fmt.Printf("%s\n", string(marshalled))
    // 输出: {"users":[["foo",{"name":"foo","age":42}],["bar",{"name":"bar","age":21}],["baz",{"name":"baz"}]]}
}

比较

元组从第一个元素到最后一个元素依次比较:

fmt.Println(tuple.Equal3(tuple.New3(1, 2, 3), tuple.New3(3, 3, 3))) // false
fmt.Println(tuple.LessThan3(tuple.New3(1, 2, 3), tuple.New3(3, 2, 1))) // true

tups := []tuple.T3{
    tuple.New3("foo", 2, -23),
    tuple.New3("foo", 72, 15),
    tuple.New3("bar", -4, 43),
}
sort.Slice(tups, func (i, j int) {
    return tuple.LessThan3(tups[i], tups[j])
})

fmt.Println(tups) // [["bar", -4, 43], ["foo", 2, -23], ["foo", 72, 15]]

比较结果

// Compare*函数返回OrderedComparisonResult值
result := tuple.Compare3(tuple.New3(1, 2, 3), tuple.New3(3, 2, 1))

// OrderedComparisonResult值是包装的整数
fmt.Println(result) // -1

// OrderedComparisonResult提供了多种方法来以更可读的方式查看结果
fmt.Println(result.GreaterThan()) // false

自定义比较

type person struct {
    name string
    age  int
}

func (p person) CompareTo(guest person) tuple.OrderedComparisonResult {
    if p.name < guest.name {
        return -1
    }
    if p.name > guest.name {
        return 1
    }
    return 0
}

func main() {
    tup1 := tuple.New2(person{name: "foo", age: 20}, person{name: "bar", age: 24})
    tup2 := tuple.New2(person{name: "bar", age: 20}, person{name: "baz", age: 24})

    fmt.Println(tuple.LessThan2C(tup1, tup2)) // true
}

格式化

元组实现了StringerGoStringer接口:

fmt.Printf("%s\n", tuple.New2("hello", "world"))
// 输出:
// ["hello" "world"]

fmt.Printf("%#v\n", tuple.New2("hello", "world"))
// 输出:
// tuple.T2[string, string]{V1: "hello", V2: "world"}

注意事项

  1. 为了比较元组,所有元组元素必须匹配constraints.Ordered
  2. 元组代码和测试代码是由scripts/gen/main.go脚本生成的
  3. 生成是通过使用Go的text/template引擎读取tuple.tpltuple_test.tpl来工作的

更多关于golang实现泛型元组数据结构的插件库go-tuple的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现泛型元组数据结构的插件库go-tuple的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


go-tuple: Golang泛型元组数据结构库使用指南

go-tuple 是一个为Golang设计的泛型元组(Tuple)实现库,它利用Go 1.18引入的泛型特性,提供了类型安全的元组数据结构。

安装

go get github.com/barweiss/go-tuple

基本用法

创建元组

package main

import (
	"fmt"
	"github.com/barweiss/go-tuple"
)

func main() {
	// 创建二元组
	t2 := tuple.New2("hello", 42)
	fmt.Printf("二元组: %v\n", t2)

	// 创建三元组
	t3 := tuple.New3("go", 1.18, true)
	fmt.Printf("三元组: %v\n", t3)

	// 创建四元组
	t4 := tuple.New4("tuple", 4, 3.14, 'π')
	fmt.Printf("四元组: %v\n", t4)
	
	// 最多支持九元组
	t9 := tuple.New9(1, 2, 3, 4, 5, 6, 7, 8, 9)
	fmt.Printf("九元组: %v\n", t9)
}

访问元组元素

// 访问二元组元素
name, age := t2.V1, t2.V2
fmt.Printf("Name: %s, Age: %d\n", name, age)

// 访问三元组元素
lang, version, isCool := t3.V1, t3.V2, t3.V3
fmt.Printf("Language: %s, Version: %.2f, IsCool: %t\n", lang, version, isCool)

// 访问四元组元素
word, num, pi, symbol := t4.V1, t4.V2, t4.V3, t4.V4
fmt.Printf("Word: %s, Num: %d, Pi: %.2f, Symbol: %c\n", word, num, pi, symbol)

元组比较

// 创建两个相同类型的元组进行比较
t2a := tuple.New2("a", 1)
t2b := tuple.New2("a", 1)
t2c := tuple.New2("b", 2)

fmt.Println("t2a == t2b:", t2a.Equal(t2b)) // true
fmt.Println("t2a == t2c:", t2a.Equal(t2c)) // false

元组作为函数返回值

func getUserInfo(id int) tuple.T2[string, int] {
	// 模拟数据库查询
	name := fmt.Sprintf("User%d", id)
	age := 20 + id%10
	return tuple.New2(name, age)
}

func main() {
	user := getUserInfo(42)
	fmt.Printf("User: %s, Age: %d\n", user.V1, user.V2)
}

元组作为Map的键

func main() {
	// 使用元组作为map的键
	userScores := make(map[tuple.T2[string, int]]int)
	
	userScores[tuple.New2("Alice", 25)] = 95
	userScores[tuple.New2("Bob", 30)] = 88
	
	score, exists := userScores[tuple.New2("Alice", 25)]
	if exists {
		fmt.Println("Alice's score:", score)
	}
}

高级用法

元组解构

func processUser(info tuple.T2[string, int]) {
	name, age := info.V1, info.V2
	fmt.Printf("Processing %s, age %d\n", name, age)
}

func main() {
	user := tuple.New2("Charlie", 35)
	processUser(user)
}

元组切片

func main() {
	users := []tuple.T2[string, int]{
		tuple.New2("Alice", 25),
		tuple.New2("Bob", 30),
		tuple.New2("Charlie", 35),
	}
	
	for _, user := range users {
		fmt.Printf("%s is %d years old\n", user.V1, user.V2)
	}
}

自定义元组类型

type UserInfo tuple.T2[string, int]

func (u UserInfo) String() string {
	return fmt.Sprintf("%s (%d)", u.V1, u.V2)
}

func main() {
	user := UserInfo(tuple.New2("Dave", 40))
	fmt.Println(user) // 输出: Dave (40)
}

性能考虑

go-tuple 的实现非常轻量级,基本上只是对多个值的简单包装。与使用结构体相比,性能开销可以忽略不计。

限制

  1. 元组元素数量最多支持9个(T1到T9)
  2. 由于Go泛型的限制,元组元素必须是可比较的类型才能使用Equal方法

替代方案

如果你需要更灵活的元组实现,也可以考虑:

  1. 使用匿名结构体
  2. 使用多个返回值
  3. 其他类似的库如github.com/samber/go-tuple

go-tuple 的优势在于提供了标准化的元组实现和便利的方法,适合需要在代码中频繁使用元组的场景。

希望这个指南能帮助你理解和使用go-tuple库!

回到顶部