Reputation: 211
I know differences between func and method. But I am confusing for usages between:
prod:=Product{"title","brand","model"}
prod.Add()
or:
prod:=Product{"title","brand","model"}
products.Add(&prod) // products is package
Upvotes: 3
Views: 3152
Reputation:
Extending the fantastic answer by @Danilo:
package main
import "fmt"
type T struct {
i int
}
func (t *T) F() {
t = &T{1}
fmt.Println(t.i)
}
func F(t *T) {
fmt.Println(t.i)
}
func main() {
t := T{2}
(&t).F()
F(&t)
}
The type of the method func (t *T) F()
is the type of the function func F(t *T)
with the receiver (t *T)
as first argument.
Upvotes: 0
Reputation: 8390
These are two distinct cases, one which is a method belongs to Product
instance and one is a global function belongs to products
package.
type Product struct {
Title string
Brand string
Model string
}
// This method add value to a field in Product
func (p *Product) Add(field, value string) {
switch field {
case "Title":
p.Title = value
case "Brand":
p.Brand = value
case "Model":
p.Model = value
}
}
The above provide a method to add value to itself as an instance of Product
, i.e.
product1 := &Product{}
product1.Add("Title", "first_title")
The second case is a public function exposed from a product
package. In this case, an instance (or a pointer) of a Product
must be supplied as an argument.
package products
func Add(p *Product, field, value string) {
// Same switch-case as above
}
Add
function then can be used from any other package.
package main
import (
"path/to/products"
)
type Product struct {
// ...
}
func main() {
product1 := &Product{}
products.Add(product1, "Title", "first_title")
Normally in your scenario, the first approach is preferred since it encapsulates the functionality of managing its attributes to itself.
The second scenario might be seen as a "class method approach" (for those coming from OOP like Python or Java) where the package is similar to class and the exposed functions similar to class methods which are more generic and can be used across many types which implement the same interface, like so:
package products
// where p is a Product interface
func Add(p Product, field, value string) {
// Same switch-case as above
}
type Product interface {
someMethod()
}
And from another package:
package main
import (
"path/to/products"
)
type Car struct {
Title string
Brand string
Model string
}
type Ship struct {
// ...
}
type Airplane struct {
// ...
}
// All types implement `Product` and can be used in `products.Add`
func (c *Car) someMethod() {}
func (s *Ship) someMethod() {}
func (a *Airplane) someMethod() {}
func main() {
plane := &Airplane{}
products.Add(plane, "Model", "Boeing-747")
}
Upvotes: 5
Reputation: 3327
This is expected as per the spec:
The type of a method is the type of a function with the receiver as first argument.
See https://golang.org/ref/spec#Method_declarations
So when you declare the Add
method on Product
, you get a function that accepts a pointer to a Product
as its first argument. So you end up with
func (p *Product) Add()
being translated to
func Add(p *Product)
So both your calls are valid and end up doing the same
Upvotes: 2