我正在尝试用 golang 实现
Iterator
。
我这样写了Iterator
界面:
type Iterator[Item any] interface {
HasNext() bool
Next() Item
Iter() Iter[Item, Iterator[Item]]
}
另外,我定义了
Iter
来包裹 Iterator
:
type Iter[I any, T Iterator[I]] struct {
Iter T
}
func New[I any, T Iterator[I]](iter T) Iter[I, T] {
return Iter[I, T]{
Iter: iter,
}
}
然后我定义了一个
Vector
来测试我的迭代器,代码的一部分:
type Vector[Item any] struct {
data []Item
// used by iterator.
idx int
}
func (v *Vector[Item]) Get(pos int) Item {
if pos < 0 || pos >= v.Size() {
panic("ouf off range")
}
return v.data[pos]
}
func (v *Vector[Item]) HasNext() bool {
return v.idx < v.Size()
}
func (v *Vector[Item]) Next() Item {
v.idx = v.idx + 1
return v.Get(v.idx - 1)
}
func (v *Vector[Item]) Iter() iterator.Iter[Item, iterator.Iterator[Item]] {
return iterator.Iter[Item, iterator.Iterator[Item]]{
Iter: v,
}
}
最后我运行这段代码:
func main() {
s := vector.New[int]()
println(s)
}
但是我遇到了死锁,堆栈的一些信息:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [sync.Mutex.Lock]:
sync.runtime_SemacquireMutex(0xbbbf60?, 0xc0?, 0xc0000c93e5?)
runtime/sema.go:77 +0x25
sync.(*Mutex).lockSlow(0xc0003c9608)
sync/mutex.go:171 +0x15d
sync.(*Mutex).Lock(...)
sync/mutex.go:90
cmd/compile/internal/types2.(*Named).resolve(0xc0003c95e0)
cmd/compile/internal/types2/named.go:164 +0x6c
cmd/compile/internal/types2.(*Named).TypeParams(...)
cmd/compile/internal/types2/named.go:310 ... cmd/compile/internal/types2.(*Checker).checkFiles(0xc0001401e0, {0xc00009ea00, 0x2, 0x2})
cmd/compile/internal/types2/check.go:371 +0x21e
cmd/compile/internal/types2.(*Checker).Files(...)
cmd/compile/internal/types2/check.go:332
cmd/compile/internal/types2.(*Config).Check(0xc0003bfc80, {0xc0000c2030?, 0x127e540?}, {0xc00009ea00, 0x2, 0x2}, 0xc0003bfce0)
cmd/compile/internal/types2/api.go:437 +0x14f
cmd/compile/internal/noder.checkFiles({0x0, {0x0, 0x0}}, {0xc00009e6c0, 0x2, 0x18?})
cmd/compile/internal/noder/irgen.go:70 +0x486
cmd/compile/internal/noder.writePkgStub({0x0?, {0x0?, 0x0?}}, {0xc00009e6c0, 0x2, 0x2})
cmd/compile/internal/noder/unified.go:210 +0x6a
cmd/compile/internal/noder.unified({0x0?, {0x0?, 0x0?}}, {0xc00009e6c0?, 0xb88540?, 0xc0000cb8f8?})
cmd/compile/internal/noder/unified.go:75 +0x85
cmd/compile/internal/noder.LoadPackage({0xc0000d4120, 0x2, 0xe})
cmd/compile/internal/noder/noder.go:77 +0x450
cmd/compile/internal/gc.Main(0xc74ae0)
cmd/compile/internal/gc/main.go:198 +0xc17
但是为什么呢?我测试了一下,发现问题出在接口中的Iter方法及其在Vector中的实现。
当它们同时存在时就会出现死锁,我推测死锁可能发生在编译时。
我不太擅长泛型,你能给我一些更好的建议吗?
谢谢您的回答!(,,€^€,,)
我之前发现了与您在评论中引用的问题@jub0bs所遇到的相同恐慌相关的类似问题(感谢您的链接和引用顺便说一句):
fatal error: all goroutines are asleep - deadlock!
这是由递归引用泛型类型引起的,当您想要返回泛型类型作为其父泛型类型时,通常可以重现。我制作了一个完整的复制存储库,其中包含所有不应该发生的行为(除了我们是否应该编写这样的泛型代码),当我尝试调查此类问题并尝试向 Golang 团队报告时,您可能需要采取行动看看它。
虽然 Golang 团队成员已将其识别为与包中的实现和检查相关的编译器错误
type2
,而像 fatal error
这样的恐慌不应该只发生在某些行为不稳定和不一致的情况下, Golang团队成员也纷纷表示,这样的定义确实是禁止的,也是不允许的。
我的建议是,您可能需要考虑使用另一种方法将迭代器方法实现为参数传递模式,而不是基于接收器的(或链式调用,如果您愿意的话)。