I'm trying to build a variadic function for a constructor in golang and I've ran into an interesting issue. This function is working...
package main
import "fmt"
type person struct {
name string
}
// This is working, but a really Not how I want to do this
func personConstructor(params ...string) person {
name := "Unnamed Person" // Default name
if len(params) > 0 {
name = params[0]
}
return person{name: name}
}
func main() {
bob := personConstructor("Bob")
}
https://play.golang.org/p/dcAdHEQtYz
And yet this, isn't.
package main
import "fmt"
type person struct {
name string
}
// This isn't working
func (p person) constructor(params ...string) person {
name := "Unnamed Person" // Default name
if len(params) > 0 {
name = params[0]
}
return person{name: name}
}
func main() {
bob := person.constructor("Bob")
}
https://play.golang.org/p/YiTQctu-1A
Any idea as to why this is?
The introduction in the Go tour provides a concise answer to your question.
Go does not have classes. However, you can define methods on types.
Your examples assume that the constructor
function is defined on the definition of the person
struct. This is not the case. A method operates on an instance of a type referred to as a receiver. A constructor is not possible in this mechanism. The established pattern within the Go community is to use a factory function to initialize a struct and is exemplified in your first function definition.
The second example provided is failing because constructor
is expecting to be called on an instance of a person which is undefined. If you construct a new instance of a person
struct the function behaves as expected.
// https://play.golang.org/p/5XDGSTMVj9
func (p person) constructor(params ...string) person {
name := "Unnamed Person" // Default name
if len(params) > 0 {
name = params[0]
}
return person{name: name}
}
func main() {
// Lets define a new instance of a person struct
p := person{}
// The function, when called on a instance, works as expected
bob := p.constructor("Bob")
fmt.Printf("%+v
", bob)
}
This illustrates that methods are attributed to an instance of a particular type.
Your problem has nothing to do with variadics.
You need to read and learn about method expressions :
https://golang.org/ref/spec#Method_expressions
package main
type person struct {
name string
}
func (p person) constructor(params ...string) person {
name := "Unnamed Person" // Default name
if len(params) > 0 {
name = params[0]
}
return person{name: name}
}
func main() {
// THIS WORKS
person.constructor(person{},"Bob")
}
This compiles but it makes very little sense to do that in your case. the constructor function expect a person receiver. Whether you put it before like
like person{}.constructor("bob")
or after like person.constructor(person{},"bob")
doesn't matter. constructor expects a person receiver . constructor method is not a "field of some person namespace", this isn't javascript.
If you want to write a constructor function write a factory without a receiver
func NewPerson(params...string)*Person{
// code
}
that's the idiomatic way to do that in Go.
I suggest you to go through the spec once at least.