在函数调用中发生类型参数恐慌

huangapple go评论87阅读模式
英文:

Type Parameter Panicking in Function Call

问题

我在Go语言中有一个表示状态的结构体,现在我想要能够比较两个状态(当前状态和期望状态),其中每个字段都与另一个字段进行比较。如果所有字段都相等,我将定义两个状态为"相等"。然而,在某些情况下,字段的相等性比较宽松,我希望能够自定义定义。

假设状态字段之一是"RestartedAfter"。如果当前状态的"RestartedAfter"大于期望状态的"RestartedAfter",那么我认为这两个状态是"相等"的。

在这个示例中,我只使用了一个字段,但是由于我想要迭代结构体的所有字段(在下一步中),我考虑使用类型参数来定义一个AssertEqual()接口,所有状态结构体中的字段都应该实现。

type StateField[T any] interface {
	AssertEqual(T) error
}

type RestartedAfter int

func (current RestartedAfter) AssertEqual(desired RestartedAfter) error {
    if current >= desired {
        return nil
    }
	return errors.New("current RestartedAfter happened before desired RestartedAfter")
}

func compareTwo[T any](x StateField[T], y T) error {
	return x.AssertEqual(y)  // panics
}

func main() {
	r1 := RestartedAfter(1)
	r2 := RestartedAfter(2)

	err := compareTwo[RestartedAfter](r1, r2)
	if err != nil {
		os.Exit(1)
	}
}

然而,这个示例会导致程序崩溃。我得到以下错误信息:"panic: interface conversion: main.StateField[go.shape.int_0] is main.RestartedAfter, not main.RestartedAfter (types from different scopes)"。

有什么想法是出了什么问题吗?

英文:

I have a struct in Go, which represents a state. I now want to be able to compare two states (current & desired),
whereby each field is compared with the other. I define two states as "equal" if all fields are "equal".
However, in some cases, field equality is rather loose, which I want to be customely define.

Let's say one of the state fields in "RestartedAfter". If current-state RestartedAfter is greater than desired-state
RestartedAfter, then I consider the two "equal".

In the example I only use a single field, but since I want to iterate over all fields of the struct (in the next step),
I thought about using type parameters to define an AssertEqual() interface, which all fields in the state-struct
should implement.

type StateField[T any] interface {
	AssertEqual(T) error
}

type RestartedAfter int

func (current RestartedAfter) AssertEqual(desired RestartedAfter) error {
    if current >= desired {
        return nil
    }
	return errors.New("current RestartedAfter happened before desired RestartedAfter")
}

func compareTwo[T any](x StateField[T], y T) error {
	return x.AssertEqual(y)  // panics
}

func main() {
	r1 := RestartedAfter(1)
	r2 := RestartedAfter(2)

	err := compareTwo[RestartedAfter](r1, r2)
	if err != nil {
		os.Exit(1)
	}
}

This example however panics. I get the following message: panic: interface conversion: main.StateField[go.shape.int_0] is main.RestartedAfter, not main.RestartedAfter (types from different scopes).

Any ideas of what's wrong?

答案1

得分: 4

我相信这是一个在这里描述的错误:
https://github.com/golang/go/issues/53376

要在当前版本中修复,你可以重新分配变量:

func compareTwo[T any](x StateField[T], y T) error {
	a := x
	b := y
	return a.AssertEqual(b)
}

在最新的开发分支中,不需要修复就可以正常工作:
https://go.dev/play/p/KAPDHQW8RWH?v=gotip

英文:

I believe this is a bug described here:
https://github.com/golang/go/issues/53376

To fix in current version you can reassign the variables:

func compareTwo[T any](x StateField[T], y T) error {
	a := x
	b := y
	return a.AssertEqual(b)
}

It works without the fix in latest dev branch:
https://go.dev/play/p/KAPDHQW8RWH?v=gotip

huangapple
  • 本文由 发表于 2022年7月12日 17:45:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/72950258.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定