如何将字符串枚举与方法一起作为泛型参数使用?

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

How to use a string enum with a method as a generic parameter?

问题

我有多个基于字符串的枚举类型,它们共享一个名为Validate()的公共方法(都在我控制之外)。我想要一个通用的方法,将字符串转换为这些枚举类型,并在结果枚举上调用Validate()方法。我尝试使用泛型来实现这一点,但由于各种原因失败了。

在下面的示例中,类型约束太强,阻止了对Validate()的调用。我还尝试过插入自己的带有Validate()方法的接口,并将其用作类型约束,但在类型转换部分失败了。

如何在不修改枚举类型的情况下实现这一点?

package main

// 假设我无法控制的情况下有多个这样的类型
type FooStatusEnum string

func NewFooStatusEnum(value FooStatusEnum) *FooStatusEnum {
	return &value
}

const (
	FooStatusEnumA FooStatusEnum = "A"
	FooStatusEnumB FooStatusEnum = "B"
	FooStatusEnumC FooStatusEnum = "C"
)

func (m FooStatusEnum) Validate() error {
	return nil
}

func stringToValidatedEnum[E ~string](s string) E {
	e := E(s)
	if err := e.Validate(); err != nil {
		panic(1)
	}
	return e
}

func main() {
	stringToValidatedEnum[FooStatusEnum]("A")
	e := FooStatusEnum("A")
	e.Validate()
}
英文:

I have multiple string-derived enums that share a common Validate() method (all outside of my control). I would like a generic method that converts a string to those enums and calls Validate() on the resulting enum. I've tried to achieve this with generics but failed for various reasons.

In the example below the type constrained is too strong and prevents a call to Validate(). I've also tried inserting my own interface with a Validate() method and use it as a type constrained, but then failed on the type conversion part.

How can I achieve this without modifying the enums?

package main

// imagine i have multiple of those types outside of my control
type FooStatusEnum string

func NewFooStatusEnum(value FooStatusEnum) *FooStatusEnum {
	return &value
}

const (
	FooStatusEnumA FooStatusEnum = "A"
	FooStatusEnumB FooStatusEnum = "B"
	FooStatusEnumC FooStatusEnum = "C"
)

func (m FooStatusEnum) Validate() error {
	return nil
}

func stringToValidatedEnum[E ~string](s string) E {
	e := E(s)
	if err := e.Validate(); err != nil {
		panic(1)
	}
	return e
}

func main() {
	stringToValidatedEnum[FooStatusEnum]("A")
	e := FooStatusEnum("A")
	e.Validate()
}

答案1

得分: 4

使用类型约束来同时指定string底层类型和Validate()方法:

type enumString interface {
	~string
	Validate() error
}

func stringToValidatedEnum[E enumString](s string) E {
	e := E(s)
	if err := e.Validate(); err != nil {
		panic(1)
	}
	return e
}

// 测试:
result := stringToValidatedEnum[FooStatusEnum]("A")
fmt.Printf("%T %v", result, result)

这将输出(在Go Playground上尝试):

main.FooStatusEnum A
英文:

Use a type constraint that both specifies string underlying type and the Validate() method:

type enumString interface {
	~string
	Validate() error
}

func stringToValidatedEnum[E enumString](s string) E {
	e := E(s)
	if err := e.Validate(); err != nil {
		panic(1)
	}
	return e
}

Testing it:

result := stringToValidatedEnum[FooStatusEnum]("A")
fmt.Printf("%T %v", result, result)

This will output (try it on the Go Playground):

main.FooStatusEnum A

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

发表评论

匿名网友

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

确定