Methods
In Go, a method is a function that has a known receiver.
If you’ve used Java language before , you will know that methods are declared inside the class:
public class User {
String name;
public String SayHello(){ // the method are declared inside the User class.
return name + " : l love you !";
}
}
public class Main {
public static void main(String[] args) { // this main method is similar to the Go's main()
User u = new User();
u.name = "Moon";
System.out.println(u.SayHello());
}
}
[output]
Moon : l love you !
This is not the case in Go. Go do it outside of the struct , the association between method and type is established by the receiver.
l think the most important different between function and method is that method are associate with a type, but function can exist independently without a type, it feels like a functional programming, a bit scala feel.
It a bit strange if you from a different background :
package main
import "fmt"
type User struct {
Name string
}
func (u User) SayHello1() string { // Method 1 : User as the method's receiver
u.Name = "Sun"
return u.Name + ": l love u ! , 1"
}
func (u *User) SayHello2() string { // Method 2 : User's pointer as the method's receiver
u.Name = "Sun"
return u.Name + ": l love u ! , 2"
}
func main() {
u := new(User)
u.Name = "Moon"
fmt.Println(u.SayHello1())
fmt.Println(u.Name)
fmt.Println(u.SayHello2())
fmt.Println(u.Name)
}
[output]
Sun: l love u ! , 1
Moon
Sun: l love u ! , 2
Sun
The combination of a (struct) type and its methods in Go is equivalent to the class in Object-Oriented Language , with a bit different ( l heard that it is more flexible and powerful , will find out - TODO).
The example above show two ways of declaring method , with a pointer receiver or a non-pointer receiver.
What is the differents ? when to use them ?
Define the method on a pointer type if you need the method to modify the data the receiver points to. Otherwise, it is often cleaner to define the method on a normal value type.
package main
import "fmt"
type User struct {
Name string
}
func (u User) change1(name string){ // Method 1 : User as the method's receiver
u.Name = name
}
func (u *User) change2(name string){ // Method 2 : User's pointer as the method's receiver
u.Name = name
}
func change3(u User, name string){
u.Name = name
}
func change4(u *User, name string){
u.Name = name
}
func main() {
var u User
u.change1("Moon1") // passed by value with a non-pointer receiver
fmt.Println("1 :", u.Name)
u.change2("Moon2") // passed by reference with a pointer receiver
fmt.Println("2 :", u.Name) // behave like Java method
change3(u, "Moon3") // passed by value using an argument
fmt.Println("3 :", u.Name)
change4(&u, "Moon4") // passed by reference using an argument
fmt.Println("4 :", u.Name)
}
[output]
1 :
2 : Moon2
3 : Moon2
4 : Moon4
If you are unsure about when to use a value or a pointer for the receiver, the Go wiki has a great set of rules that you can follow. The Go wiki also contains a paragraph about the conventions the community follows for naming receivers.
Some of the receiver's properties :
- The receiver type can be almost any type, not just struct type, even a function type or alias types for int, bool, string or array.
- The receiver cannot be an interface type, since an interface is the abstract definition and a method is the implementation; trying to do so generates the compiler error: invalid receiver type
- receiver's type must be declared within the same package. as all of its methods.
Some of the method's properties :
Methods are functions, so again there is no method overloading: for a given type, there is only one method with a given name , so the code below is valid ,
func (a *Dog) MakeNoise(n Noise) Noise func (a *Cat) MakeNoise(n Noise) Noise
because they have different types for the receivers. but not for the below :
func (c Car) Accelerate(s int){} func (c *Car) Accelerate(s int){}
Method's getter and setter,
package person type Person struct { firstName string lastName string } func (p *Person) FirstName() string { return p.firstName } func (p *Person) SetFirstName(newName string) { p.firstName = newName }
p.firstName = “Eric” will fail in another package , because Person's fields are unexported fields,
package main ... func main() { ... p := new(person.Person) p.firstName = “Eric” // error : p.firstName undefined p.SetFirstName(“Eric”) // OK }
what is the benefits of doing the way of Go instead of Java ? [TODO]
References :