英文:
how to avoid go lint duplication for same pattern with different function?
问题
我在重构Go代码时遇到了困难,因为代码检查工具检测到了模式的重复,但函数是不同的。
代码如下,它是使用protobuf定义的grpc实现的:
func (svc *UserService) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserResponse, error) {
err := svc.validateCreateUser(req)
if err != nil {
return nil, err
}
user, err := svc.repo.CreateUser(ctx, req)
if err != nil {
return nil, err
}
return user, nil
}
func (svc *UserService) UpdateUser(ctx context.Context, req *pb.UpdateUserRequest) (*pb.UpdateUserResponse, error) {
err := svc.validateUpdateUser(req)
if err != nil {
return nil, err
}
user, err := svc.repo.UpdateUser(ctx, req)
if err != nil {
return nil, err
}
return user, nil
}
提前感谢。
我不知道如何避免重复,因为这两个函数的参数类型也不同。
英文:
I have difficulties refactoring code in go, since the lint detects duplication of pattern but the function is different.
the code goes like this, it is implemented for grpc with protobuf definition
func (svc *UserService) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserResponse, error) {
err := svc.validateCreateUser(req)
if err != nil {
return nil, err
}
user, err := svc.repo.CreateUser(ctx, req)
if err != nil {
return nil, err
}
return user, nil
}
func (svc *UserService) UpdateUser(ctx context.Context, req *pb.UpdateUserRequest) (*pb.UpdateUserResponse, error) {
err := svc.validateUpdateUser(req)
if err != nil {
return nil, err
}
user, err := svc.repo.UpdateUser(ctx, req)
if err != nil {
return nil, err
}
return user, nil
}
thanks in advance.
I have no clue how to avoid duplication since the function also have different param type.
答案1
得分: 1
并非所有的lint问题都必须修复
如果你认为修复会牺牲可读性,可以添加 // nolint 注释
然而...你可以使用泛型重构代码
func [T, V any] someNameToBeDefined(
ctx context.Context,
target T,
validator func(T) error,
executor func(context.Context, T) (V, error),
) (V, error){
if err := validator(target); err!= nil { … }
return executor(ctx, target)
}
func (svc *UserService) CreateUser(
ctx context.Context,
req *pb.CreateUserRequest,
) (*pb.CreateUserResponse, error) {
return someNameToBeDefined(ctx,
req,
svc.validateCreateUser,
svc.repo.CreateUser,
)
}
如果你认为这样可读性更好,可以继续。
但也许这不是正确的方式。
例如,你的repo可以在创建/更新之前验证请求。
在我看来,这种方法比使用泛型和函数指针更可读。
英文:
Not all lint issues must be fixed
If you think it will sacrifice readability, add a // nolint
However… you can refactor them code using generics
func [T, V any] someNameToBeDefined(
ctx context.Context,
target T,
validator func(T) error,
executor func(context.Context, T) (V, error),
) (V, error){
if err := validator(target); err!= nil { … }
return executor(ctx, target)
}
func (svc *UserService) CreateUser(
ctx context.Context,
req *pb.CreateUserRequest,
) (*pb.CreateUserResponse, error) {
return someNameToBeDefined(ctx,
req,
svc.validateCreateUser,
svc.repo.CreateUser,
)
}
If you think this is readable, go ahead.
But perhaps this may not the right way.
For instance, your repo can validate the request before create/update.
This is a more readable approach than use generics and function pointers IMHO
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论