Go language basic methods and receivers

 5 minutes to read

go language basic methods and receivers

In the Go language, there is a concept that is very similar to a function called a method. A method in the Go language is actually a function that acts on the receiver. The receiver is a variable of a non-built-in type, so the method is a special type. The function.

Differences between methods and functions:
  • Functions and methods are declared differently

  • Functions can be passed as parameters, but not methods

  • Functions can be anonymous, methods cannot

  • When the function parameter is a value type, the data of the pointer type cannot be passed directly, and vice versa.

  • When the method receiver is a value type, the method can be called directly with a variable of the pointer type, and vice versa.

The declaration of a method is similar to that of an ordinary function, except that there is an additional parameter before the function name, which binds the method to the type corresponding to the parameter.

func (t Type) methodName(parameter list) {

}

The above code snippet creates a method methodName with a receiver of type Type.

  • Receiver variable t: When naming the parameter variable name in the receiver, it is officially recommended to use the first lowercase letter of the receiver type name instead of names such as self and this. For example, a receiver variable of type Socket should be named s, a receiver variable of type Connector should be named c, etc.

  • Receiver type Type: The receiver type is similar to the parameter, which can be a pointer type and a non-pointer type.

  • Method name, parameter list, return parameter: the format is the same as the function definition.

Methods can belong not only to struct types, but also to any other custom types that are not interface or pointer types.

We can use the Go language type to define a type that has the same function as int. This type cannot be regarded as an alias of the int type, they belong to different types and cannot be directly assigned to each other.

package main

import "fmt"

// 将newInt定义为int类型
type newInt int

func (n newInt) Add(b newInt) newInt {
	return n + b
}

func main() {
	var a newInt
	a = 100
	fmt.Println(a)        // 100
	fmt.Printf("%T\n", a) // main.newInt
	fmt.Println(a.Add(10))
}

A method is a special function, defined on a specific type, and invoked through an instance of the type, which is called the receiver.

The receiver must have an explicit name, which must be used in the method

The receiver type must be declared in the same package as the method

Method names of the same type are not allowed to be repeated

The Go language does not allow adding methods for simple built-in types, and the methods defined below are illegal.

func (a int) Add(b int) {
	fmt.Println(a+b)
}

Why do we need methods when we already have functions?

  • Go is not a pure object-oriented programming language, and Go does not support classes, so a type-based approach is a way to achieve class-like behavior.

  • Methods with the same name can be defined on different types, while functions with the same name are not allowed.

Suppose we have a Square and Circle structure, we can define an Area method on Square and Circle respectively, see the following program for details.

package main

import (
	"fmt"
	"math"
)

type Rectangle struct {
	length int
	width  int
}

type Circle struct {
	radius float64
}

func (r Rectangle) Area() int {
	return r.length * r.width
}

func (c Circle) Area() float64 {
	return math.Pi * c.radius * c.radius
}

func main() {
	r := Rectangle{
		length: 10,
		width:  10,
	}
	fmt.Printf("Area of rectangle %d\n", r.Area())
	c := Circle{
		radius: 10,
	}
	fmt.Printf("Area of circle %f", c.Area())
}
Pointer receivers and value receivers

The difference between value receivers and pointer receivers is that changes inside the methods of pointer receivers are visible to the caller, while value receivers are not.

package main

import "fmt"

type Person2 struct {
	Name string
	Age  int
}

func (p Person2) SetName(name string)  {
	p.Name=name
}

func (p *Person2) SetAge(age int)  {
	p.Age=age
}

func (p *Person2) getName() string {
	return p.Name
}

func (p *Person2) getAge() int {
	return p.Age
}


func main() {
	p1:=new(Person2)
	p1.SetName("John")
	p1.SetAge(18)
	fmt.Println(p1.getName())
	fmt.Println(p1.getAge())

	p2:=Person2{}
	p2.SetName("bruce")
	p2.SetAge(19)  //使用值类型来调用指针接收器
	fmt.Println(p2.getName())
	fmt.Println(p2.getAge())
}

The results are as follows:


18

19

The instance p1 of the pointer type and the instance p2 of the value type are created respectively above, but whether it is p1 or p2, the name value set by the SetName() method does not affect the name value in the original instance, so getName() all output null string, And the age value set by them calling the setAge() method affects the age value in the original instance.

We call the pointer receiver method SetAge through p2. This is allowed. For convenience, the Go language interprets the code p2.SetAge(19) as (&p2).SetAge(19)

How to choose the receiver type

Small objects in the computer are suitable for non-pointer receivers due to the speed of value copying.

Large objects are suitable for using pointer receivers because of low copy performance. When passing between receivers and parameters, no copying is performed, and only pointers are passed.

If there is a need to modify member variables, use pointer-type receivers.