Golang类型系统详解

Golang类型系统详解 我正在寻找一些链接来解释(希望用简单的术语)Go语言的类型系统。

我能够使用Go语言的类型系统,但我发现当我开始偏离常规路径时,我是在猜测Go语言的类型系统有哪些可能性。

示例:我尝试解决一个创建惰性斐波那契生成器的问题(如下)。

基本的斐波那契函数(fib)

func fib(n uint) uint {
	if n == 0 {
		return 0
	} else if n == 1 {
		return 1
	} else {
		return fib(n-1) + fib(n-2)
	}
}

创建一个类型来帮助实现惰性斐波那契生成器函数。

type Func[T any] func() (T, Func[T])//doesn't need to be generic but what the heck!

生成器函数,它返回计算出的斐波那契元素和一个函数,该函数返回下一个斐波那契元素以及用于(下一个+1)等的生成器函数。

func cal_fib_elem_and_next(n uint) (uint, Func[uint]) {
	return fib(n), Func[uint](func() (uint, Func[uint]) { return cal_fib_elem_and_next(n + 1) })
}

用法。

func main() {
	n, next_func := cal_fib_elem_and_next(20)
	fmt.Printf("elem: %d, %T\n", n, next_func)
	n, next_func = next_func()
	fmt.Printf("elem: %d, %T\n", n, next_func)
	n, next_func = next_func()
	fmt.Printf("elem: %d, %T\n", n, next_func)
	n, next_func = next_func()
	fmt.Printf("elem: %d, %T\n", n, next_func)
}

输出:

elem: 6765, main.Func[uint] elem: 10946, main.Func[uint] elem: 17711, main.Func[uint] elem: 28657, main.Func[uint]

我是通过尝试(猜测)得出这个解决方案的……我之前并不知道Go语言的类型系统是否能处理这种情况。

我发现,当你在常规路径上时,Go语言的类型系统有很好的文档记录,但一旦你偏离了那条常规路径……你就只能靠自己了。


更多关于Golang类型系统详解的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

嗯,有这份 Go 编程语言规范 - Go 编程语言,但它没有太多的阐述或简单的术语。它确实涵盖了一切。

每当我看到斐波那契数列生成器时,它通常是函数式编程教程的一部分,尽管 Go 拥有一等函数,但它并不是真正为你在纯函数式编程语言中会使用的那种编程风格而设计的。例如,它没有尾调用优化。

更多关于Golang类型系统详解的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


作为一个不熟悉函数式编程语言的人,我不太确定你寻找的是语言规范中未涵盖的哪些内容。你的示例看起来是可行的,但可能会带来巨大的性能影响。我认为你返回的闭包是一个独立的内存分配,而且正如之前提到的,Go语言没有尾调用优化。

func main() {
    fmt.Println("hello world")
}

Go的类型系统确实支持你这种高阶函数模式。你的代码展示了Go类型系统的一个重要特性:函数类型可以作为一等公民使用,包括作为参数、返回值和自定义类型的底层类型。

// 你的Func类型定义是正确的
type Func[T any] func() (T, Func[T])

// 更高效的惰性斐波那契实现
func lazyFib() Func[int] {
    var prev, curr int = 0, 1
    
    return Func[int](func() (int, Func[int]) {
        ret := prev
        prev, curr = curr, prev+curr
        return ret, lazyFib()
    })
}

// 使用闭包状态保持的实现
func lazyFibClosure() func() int {
    a, b := 0, 1
    return func() int {
        ret := a
        a, b = b, a+b
        return ret
    }
}

func main() {
    // 使用你的Func类型
    fibFunc := lazyFib()
    val, next := fibFunc()
    fmt.Println(val) // 0
    
    val, next = next()
    fmt.Println(val) // 1
    
    // 使用闭包版本
    fib := lazyFibClosure()
    fmt.Println(fib()) // 0
    fmt.Println(fib()) // 1
    fmt.Println(fib()) // 1
    fmt.Println(fib()) // 2
}

Go的类型系统支持以下高阶用法:

// 函数作为类型参数
func Map[T, U any](s []T, f func(T) U) []U {
    result := make([]U, len(s))
    for i, v := range s {
        result[i] = f(v)
    }
    return result
}

// 函数作为结构体字段
type Transformer struct {
    transform func(int) int
}

// 函数作为接口实现
type Handler interface {
    Handle() error
}

type FuncHandler func() error

func (f FuncHandler) Handle() error {
    return f()
}

func main() {
    // 函数类型转换
    var h Handler = FuncHandler(func() error {
        return nil
    })
    h.Handle()
}

你的实现是正确的,Go的类型系统确实支持这种递归函数类型定义。这种模式在实现状态机、流处理或惰性求值时很有用。

回到顶部