使用结构并将其视为类来解决Golang中的依赖关系是否不好?

I wrote a lot PHP with the OOP frameworks before, and I'm learning Golang,

When I was using PHP, The class is useful that I could pass a $model in to my class then share it between functions:

class User {
   function __construct(UserModel $model) {
       $this->model = $model
   }

   function delete($id) {
       $this->model->delete($id);
   }

   function update($id) {
       $this->model->update($id);
   }
}

$UserModel = new UserModel();
$User      = new User($UserModel);
$User->delete(1);

But there's no class in Golang, I knew that I could treat structs like a class:

type User struct {
    model *models.User
}

func (u *User) Delete(id int) {
    u.model.Delete(id)
}

func (u *User) Update(id int) {
    u.model.Update(id)
}

userModel := &models.User{}
user      := User{model: userModel}
user.Delete(1)

I felt like the struct is used to store the information, and the method of the struct should be used to modify the value of the struct.

But right now I made a struct just because I want to treat it like a class and solve the dependency problem, is it bad to use such approach in Golang?

From overall conceptual standpoint there is nothing wrong in your implementation.

On a detailed view there are inconsistencies that raise questions.

In all cases below there is a potential concurrency issue due to data shared across various Delete calls.

Case A

If models.User{} does all the work, then why can't we just

userModel := &models.User{}
userModel.Delete(userId)

Case B

If User is our public interface:

user      := User{model: userModel}
user.Delete(1)

then taking userId to delete is redundant and shall be done as:

user.Delete()

userId is taken from user context.

Case C

Otherwise, we might want to make userModel to be set for all User instances:

package User;
// private package level variable
var model = userModel
func Delete(userId int) {
    model.Delete(userId)
}
...
User.Delete(userId)

Conclusion

Each case above solves the same problem with a slightly different emphasis. Case A is straightforward. Case B and C rely on underlying shared code that could be used with event notifications. Case B and C are different in User scope. In Case B User is a structure. In Case C user is a package name. I think Case C is used less often than Case B. So, if use insist on having an underlying model, then Case B is probably the most intuitive solution from user code point of view.

you can use interface with method In service (connect db)

// UserServiceInterface include method list
type UserServiceInterface interface {
    GetAll(helpers.ParamsGetAll) (models.PublicUsers, error)
    Get(int64) (models.User, error)
    Delete(int64) (bool, error)
    Create(models.User) (int64, error)
    Update(models.User) (models.User, error)
    CheckExistUsername(string) (bool, error)
    CheckExistEmail(string) (bool, error)
    CreateEmailActive(string, string, int64) error
    CheckExistUser(int64) (bool, error)
}

// UserService struct
type userService struct{}

// NewUserService to constructor
func NewUserService() userService {
    return userService{}
}

func (userService )GetAll (p helpers.ParamGetAll)(models.PublicUser, error) {
    code here....
}

In user controller

// UserController controller
type UserController struct {
    Service services.UserServiceInterface
}
    func (controller UserController) GetAll(c *gin.Context) {
    users, errGetAll := controller.Service.GetAll(params)
}