我正在导入一些具有一些公共字段的类。
package foo
type FooA struct {
...
SharedVal int
}
type FooB struct {
...
SharedVal int
}
type FooC struct {
...
SharedVal int
}
由于各种原因,我无法修改foo
包。我想有一些抽象,给我一些联合类型,这样我就可以为sharedVal
字段创建一个setter;例如像这样的
package bar
type GenericFoo = foo.FooA | foo.FooB | foo.FooC
func (f *GenericFoo) SetSharedVal(val int) {
f.SharedVal = val
}
我该怎么做?接口对我来说不起作用,因为它们需要共享方法,但Foo
类没有setter。该解决方案最好不涉及导入其他第三方包,因为在我的用例中,依赖关系管理变得很复杂。
考虑到不能修改第三方包的约束,并且没有可利用的通用接口方法,您唯一的选择是使用反射包对任何输入值执行运行时检查。
一个这样的解决方案:
import "reflect"
// setSharedVal takes a pointer to a struct with a field 'SharedVal' of type int and sets it
func setSharedVal(v any, nv int) error {
var rv reflect.Value
if rv = reflect.ValueOf(v); rv.Kind() != reflect.Ptr {
return fmt.Errorf("must pass a pointer to struct")
}
if rv = rv.Elem(); rv.Kind() != reflect.Struct {
return fmt.Errorf("must pass a pointer to struct")
}
const fieldName = "SharedVal"
rv = rv.FieldByName(fieldName)
switch rv.Kind() {
case reflect.Invalid:
return fmt.Errorf("struct has no field named %q", fieldName)
case reflect.Int:
rv.SetInt(int64(nv))
return nil
default:
return fmt.Errorf("struct field %q must be of type %q", fieldName, reflect.Int)
}
}
a, b, c := FooA{}, FooB{}, FooC{}
err = setSharedVal(&a, 1)
err = setSharedVal(&b, 2)
err = setSharedVal(&c, 3)
输出:
main.FooA{SharedVal:1}
main.FooB{SharedVal:2}
main.FooC{SharedVal:3}
https://go.dev/play/p/KwWyJBKpmiW