如何在GO中实现通用类型?
使用GO 1.18中的新仿制药,我认为可以创建一种可以使用的“ [a,b]”类型,以表明某些东西可能是A型或类型
。在这种情况下,函数可能会返回两个可能的值之一(例如,“正常”结果一个,一个用于错误)。
我知道错误的“惯用性”是返回“正常”值和错误值,为错误或值返回零。但是...让我感到困扰,我们实际上是在说“这是“返回 and b”的,我们真正要说的是'这是'这是'这是'这是'这返回a 或 b'。
因此,我认为也许我们可以在这里做得更好,我认为这也可能是一个很好的练习,可以看到/测试我们可以使用这些新仿制药的界限。
可悲的是,尽我所能,到目前为止,我还无法解决练习并获得任何工作/编译。从我的一次失败尝试中,这是我想以某种方式实现的界面:
//A value of type `Either[A,B]` holds one value which can be either of type A or type B.
type Either[A any, B any] interface {
// Call either one of two functions depending on whether the value is an A or B
// and return the result.
Switch[R any]( // <=== ERROR: interface methods must have no type parameters
onA func(a A) R),
onB func(b B) R),
) R
}
不幸的是,这很快就失败了,因为go不允许声明此接口。显然是因为“接口方法必须没有类型参数”。
我们如何解决此限制?或者根本无法在GO中创建“类型”,以准确地表达了“这东西是/返回A或B”的想法(而不是A和B的元组)。
With the new generics in Go 1.18, I thought it might be possible to create a 'Either[A,B]' type that can be used to express that something could be either of type A or type B.
A situation where you might use this is in situations where a function might return one of two possible values as a result (e.g. one for 'normal' result and one for an error).
I know the 'idiomatic' Go for errors would be to return both a 'normal' value and an error value, returning a nil for either the error or the value. But... it sort of bothers me that we are essentially saying 'this returns A and B' in the type, where what we really mean to say is 'this returns A or B'.
So I thought maybe we can do better here, and I thought this might also be a good exercise to see/test the boundaries of what we can do with these new generics.
Sadly,try as I might, so far I have not been able solve the exercise and get anything working/compiling. From one of my failed attempts, here is an interface I'd like to implement somehow:
//A value of type `Either[A,B]` holds one value which can be either of type A or type B.
type Either[A any, B any] interface {
// Call either one of two functions depending on whether the value is an A or B
// and return the result.
Switch[R any]( // <=== ERROR: interface methods must have no type parameters
onA func(a A) R),
onB func(b B) R),
) R
}
Unfortunately, this fails rather quickly because declaring this interface isn't allowed by Go. Apparantly because 'interface methods must have no type parameters'.
How do we work around this restriction? Or is there simply no way to create a 'type' in Go that accurately expresses the idea that 'this thing is/returns either A or B' (as opposed to a tuple of both A and B).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果我必须这样做,我会查找一种函数式编程语言(如 OCaml)并模仿他们任一类型的解决方案。
If I had to do this, I would look up a functional programming language(like OCaml) and knock-off their solution of the either type..
Either
可以建模为具有any
/interface{}
类型的一个未导出字段的结构类型。类型参数将用于确保某种程度的编译时类型安全:如果
Switch
必须声明为方法,则不能在R
中通过以下方式对其进行参数化:本身。附加类型参数必须在类型定义中声明,但这可能会使使用有点麻烦,因为必须在实例化时选择R
。独立的函数似乎更好 - 在同一个包中,访问未导出的字段:
带有一些代码和用法的游乐场: https://go.dev/play/p/g-NmE4KZVq2
The
Either
could be modeled as a struct type with one unexported field of typeany
/interface{}
. The type parameters would be used to ensure some degree of compile-time type safety:If
Switch
has to be declared as a method, it can't be parametrized inR
by itself. The additional type parameter must be declared on the type definition, however this might make usage a bit cumbersome because thenR
must be chosen upon instantiation.A standalone function seems better — in the same package, to access the unexported field:
A playground with some code and usage: https://go.dev/play/p/g-NmE4KZVq2
您可以使用 https://github.com/samber/mo 库(免责声明:我是项目作者)。
任一签名是:
一些示例:
您关于
Switch
模式的问题可以通过以下方式实现:You can use the https://github.com/samber/mo library (disclaimer: I'm the project author).
Either signature is:
Some examples:
Your question about a
Switch
pattern can be implemented this way:我终于找到了解决方案。关键是将“任一”类型定义为“结构”而不是接口。
这是可行的,但代价是实际上仍然在底层使用“类元组”实现,我们同时存储 A 和 B,但确保只能使用其中之一通过公共 API。
我怀疑考虑到 Go 对我们施加的限制,这是我们能做的最好的事情。
如果有人有一个“解决方法”,本质上并不使用“元组”来表示“联合”。我认为这是一个更好的答案。
A solution finally came to me. The key was defining the 'Either' type as a 'struct' instead of an interface.
That works, but at the 'price' of really still using a 'tuple-like' implementation under the hood were we store both an A and a B but ensure it is only possible to use one of them via the public API.
I suspect this is the best we can do given the restrictions Go puts on us.
If someone has a 'workaround' that doesn't essentially use 'tuples' to represent 'unions'. I would consider that a better answer.