An bad title I know, basically it comes down to these two different situations.
First if we have a create method which accepts a pointer to the model:
func Create(model *Model) error {
model, err := db.Insert(model)
if err != nil {
return err
}
return nil
}
Second we have a method which also returns the pointer
func Create(model *Model) (*Model, error) {
model, err := db.Insert(model)
if err != nil {
return nil, err
}
return model, nil
}
I was erring towards the second signature because it lets you use a literal as the argument to create and still have a reference at the end of the method.
Views?
评论:
tmornini:
ROFLLOLSTER:Why not:
func (model *Model) Create() error
tmornini:Because then you can't do:
model, err := Create(&Model{fields...})
shovelpost:Fair enough
func (model *Model) Create() (*Model, error)
Allows
model, err := &Model{fields ...}.Create()
tmornini:I don't think it is is a good idea to add database logic to your application's structs.
ROFLLOLSTER:I would have agreed with that in the past.
Now that I'm thinking purely in terms of HTTP microservice systems, I find there's no benefit in the additional complexity.
OP code implied the Create func was already in the Model struct's package.
EDIT: 180 degree turn around after thinking it through.
tmornini:They are actually in different packages, just wrote it that way for brevity because I'm on mobile.
shovelpost:All good!
dasopranos:I believe there is a 3rd option:
func Create(u User) (User, error) or func Create(u User) (*User, error)
You pass a copy with only the required values filled like say
Name
and you return a brand new user that contains the rest likeID
andCreated
.I think it makes a little more sense than:
func Create(u *User) (*User, error)
Because if we are passing a pointer then why return it? Is it the same one? If it is then why not modify the original one instead? Of course there is still the argument that
User
might be big and we do not wish to copy it. So...I think my favorite option is :
func Create(u *User) error
Where you pass a pointer and after the function ends successfully if we inspect the fields of
u
the fields likeID
andCreated
have been filled with the values from the database. It feels a little more "lightweight" to me and the fact that you pass down a pointer it means that the function is planning to modify its values.In the end I don't think it matters too much. Just be consistent across the codebase.
P.S. I know it was an example but I detest seeing things like
models.Model
withmodels
being the worst part.
tmornini:I like the second one. It makes the code smaller which is always good, and IMHO it makes it more readable too.
Infact I go even futher, i would do: https://play.golang.org/p/6e_Er9PtdH
(sorry i couldnt get reddit code formatting to work)
dasopranos:You're headed down the road to creating your own ORM.
The path to hell is paved with good intentions!
I don't see it. What I see is the orthognality of the DB and Model concepts in my program.
"Simplicity comes from orthogonality and predictability." -- Rob Pike
