Golang Goreuse - 编写可复用/通用代码的工具

Golang Goreuse - 编写可复用/通用代码的工具 有一篇关于如何编写可重用的通用可排序切片以及如何基于内置链表编写可重用的通用链表的教程。请参阅 goreuse

2 回复

我非常希望能与3月19日到访慕尼黑的Gopher们见面!我的演讲中有一部分专门介绍goreuse

更多关于Golang Goreuse - 编写可复用/通用代码的工具的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,编写可复用的通用代码通常依赖于泛型(generics)和接口(interfaces)。根据你提到的goreuse项目,它可能专注于通过泛型实现可重用的数据结构,如可排序切片和链表。下面我将提供一个示例,展示如何使用Go 1.18+的泛型特性来构建一个通用的可排序切片和一个基于内置链表的通用链表。这些代码可以直接在你的项目中复用。

示例1: 通用的可排序切片

这个示例定义了一个泛型切片类型,它可以存储任何可比较的类型,并支持排序。我们使用cmp.Ordered约束来确保元素类型支持比较操作(如<, ==, >)。

package main

import (
    "fmt"
    "sort"
)

// SortableSlice 是一个泛型切片,可以存储任何可比较的类型,并支持排序。
type SortableSlice[T cmp.Ordered] []T

// Sort 方法对切片进行升序排序。
func (s SortableSlice[T]) Sort() {
    sort.Slice(s, func(i, j int) bool {
        return s[i] < s[j]
    })
}

// Len 返回切片的长度。
func (s SortableSlice[T]) Len() int {
    return len(s)
}

// Less 比较两个元素,用于排序。
func (s SortableSlice[T]) Less(i, j int) bool {
    return s[i] < s[j]
}

// Swap 交换两个元素的位置。
func (s SortableSlice[T]) Swap(i, j int) {
    s[i], s[j] = s[j], s[i]
}

func main() {
    // 示例:使用 SortableSlice 对整数切片排序
    intSlice := SortableSlice[int]{3, 1, 4, 1, 5, 9, 2, 6}
    intSlice.Sort()
    fmt.Println("Sorted integers:", intSlice) // 输出: [1 1 2 3 4 5 6 9]

    // 示例:对字符串切片排序
    strSlice := SortableSlice[string]{"banana", "apple", "cherry"}
    strSlice.Sort()
    fmt.Println("Sorted strings:", strSlice) // 输出: [apple banana cherry]
}

示例2: 基于内置链表的通用链表

这个示例使用Go的container/list包构建一个泛型链表,允许存储任意类型的元素。我们通过包装标准链表来实现类型安全。

package main

import (
    "container/list"
    "fmt"
)

// GenericList 是一个泛型链表,可以存储任何类型的元素。
type GenericList[T any] struct {
    list *list.List
}

// NewGenericList 创建一个新的泛型链表实例。
func NewGenericList[T any]() *GenericList[T] {
    return &GenericList[T]{
        list: list.New(),
    }
}

// PushBack 在链表尾部添加一个元素。
func (gl *GenericList[T]) PushBack(value T) {
    gl.list.PushBack(value)
}

// PushFront 在链表头部添加一个元素。
func (gl *GenericList[T]) PushFront(value T) {
    gl.list.PushFront(value)
}

// Front 返回链表的第一个元素。
func (gl *GenericList[T]) Front() T {
    if gl.list.Front() != nil {
        return gl.list.Front().Value.(T)
    }
    var zero T
    return zero
}

// Back 返回链表的最后一个元素。
func (gl *GenericList[T]) Back() T {
    if gl.list.Back() != nil {
        return gl.list.Back().Value.(T)
    }
    var zero T
    return zero
}

// Len 返回链表的长度。
func (gl *GenericList[T]) Len() int {
    return gl.list.Len()
}

// Iterate 遍历链表并应用一个函数到每个元素。
func (gl *GenericList[T]) Iterate(f func(T)) {
    for e := gl.list.Front(); e != nil; e = e.Next() {
        f(e.Value.(T))
    }
}

func main() {
    // 示例:使用 GenericList 存储整数
    intList := NewGenericList[int]()
    intList.PushBack(10)
    intList.PushFront(5)
    intList.PushBack(20)
    fmt.Println("List length:", intList.Len()) // 输出: 3
    fmt.Println("Front element:", intList.Front()) // 输出: 5
    fmt.Println("Back element:", intList.Back())   // 输出: 20

    // 遍历链表并打印每个元素
    intList.Iterate(func(val int) {
        fmt.Println("Element:", val)
    })
    // 输出:
    // Element: 5
    // Element: 10
    // Element: 20

    // 示例:存储字符串
    strList := NewGenericList[string]()
    strList.PushBack("world")
    strList.PushFront("hello")
    strList.Iterate(func(val string) {
        fmt.Println(val)
    })
    // 输出:
    // hello
    // world
}

说明

  • 可排序切片:通过泛型SortableSlice,你可以对任何可比较类型(如intfloat64string)的切片进行排序,而无需为每种类型重写代码。
  • 通用链表GenericList包装了标准链表,提供了类型安全的方法来操作元素,避免了类型断言错误。
  • 这些代码利用了Go 1.18引入的泛型特性,确保类型安全并减少重复代码。你可以直接将这些结构体和方法集成到你的项目中,实现高度可复用的通用数据结构。

如果你在使用过程中遇到问题,例如类型约束或性能优化,可以参考Go官方文档或社区资源进行调试。

回到顶部