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 :

  1. Methods, Interfaces and Embedded Types in Go By William Kennedy

results matching ""

    No results matching ""