I am confused in following two approaches about when to use a public method and when to use a getter method ,and which is better approach
I have this file in packagea
package packagea
type A struct {
name string
email string
}
func (a *A) NewMock() *A {
return &A{"logan", "rrrr"}
}
func NewMock2() *A {
return &A{"logan", "rrrr"}
}
And this file in package demo
package demo
func GetIt() {
b := new(packagea.A)
a := b.NewMock() // Using getter
c := packagea.NewMock2() //directly calling the method
fmt.Println(a) //&{logan rrrr}
fmt.Println(c) //&{logan rrrr}
}
They both print the same thing ,but I am confused when to use which .Please help me out.Thanks
CodePudding user response:
In general a constructor of an object should be a plain function, so your second example is fine.
It is good to have a function to construct your object if there is many fields or you have some small logic or validation.
For simple object like your example, allocating the object directly and made the fields public will be also good.
In your first example you allocate an object b
, just for the sake of calling a method to allocate the object you really want.
An this is not good, as to pollute the memory with objects you never need.
b
is built by assigning default values to the struct's fields, that are empty strings.
If the default values are just fine, you can think to adopt specific setter methods, instead of a constructor.
func (a *A) SetName(n: string) {
a.name = n
}
func (a *A) SetEmail(e: string) {
a.email = e
}
CodePudding user response:
Philosophically speaking
If you want your constructor to handle allocating and creating a default struct value for you then:
package packagea func NewMock2() *A { return &A{"logan", "rrrr"} }
If you want your constructor to handle creation and initialization to provided arguments:
package packagea func NewMock2(name, email string) *A { return &A{name, email} }
If you want creation to be decoupled and your constructor does not need to bother how or where the value was created and only update attribute values:
package packagea type A struct { name string email string } func (a *A) NewA(name string, email string) { if a == nil { panic(fmt.Errorf("nil pointer")) } a.name = name a.email = email }
CodePudding user response:
First, you need to understand
how new
function works
In Go new is built-in functions that allocate memory but not it does not initialize the memory.
here b := new(packagea.A)
it allocates the memory and returns the pointer to that memory so that you can access that memory by using that pointer.
because b is a pointer you can initial value for name
and email
like this
b.name = "FOO"
b.email = "[email protected]"
but here you have a method which is a pointer receiver.
func (a *A) NewMock() *A {
return &A{"logan", "rrrr"} //composite literals.
}
so here you are repeating the same thing allocation of memory (which is already done by new function) and initializing the value in memory. Don't repeat yourself.
Now Let's talk about the second way.
c := packagea.NewMock2() //directly calling the method
func NewMock2() *A {
return &A{"logan", "rrrr"}
}
here you doing a simple thing which is allocation of memory and initializing the value in memory.
but I am confused about when to use which. Please help me out.
When to use new
function when there is no need for initialization. for Example
type A struct {
buffer bytes.Buffer
}
like here when you do this b := new(A)
now the zero value for Buffer is an empty buffer ready to use. so use new when no need of initialization and ready to use. new always returns "Pointer" and default zero value again the type.
here NewMock2()
is also a function but with your own logic inside it with full control. you can pass parameters or not. you can return value sematic or pointer sematic it is up to you. You can think like this before running the Car you need to initialize the car components because you cannot run the car if the car is not initialized.