Go Language Programming-Chapter 6--Methods

Go Language Programming – Chapter 6 – Methods

An object is simply a value or variable and has its methods, which are functions of a specific type.

6.1 Method declaration

The declaration of a method is similar to the declaration of an ordinary function, except that there is an additional parameter in front of the function name. This parameter binds this method to the type corresponding to this parameter.

package geometry

import "math"

type Point struct {
    
     X, Y float64 }

// 普通函数
func Distince(p, q Point) float64 {
    
    
	return math.Hypot(q.X - p.X, q.Y - p.Y)
}

// Point 类型的方法
func (p Point)Distince(q Point) float64 {
    
    
	return math.Hypot(q.X - p.X, q.Y - p.Y)
}

The additional parameter p is called the receiver of the method. The receiver does not use special names (such as this or self).

The expression p.Distance is called 选择子(selector)because it selects the appropriate Distince method for the recipient p.

6.2 Methods of pointer receivers

Since the calling function copies each argument variable, if the function needs to update a variable, or if an argument is too large and we want to avoid copying the entire argument. We have to use pointers to pass the address of the variable.

func (p *Point) ScaleBy(factor float64) {
    
    
	p.X *= factor;
	p.Y *= factor;
}

Command types (Point) and pointers to them (*Point) are the only types that can appear at receiver declarations.
In a real program, if any Point method uses a pointer receiver, then all Point methods should use pointer receivers.

If the method requires a *Point receiver, we can use the shorthand:

p.ScaleBy(2)

The compiler performs &pprivacy conversions on variables. This is only allowed for variables, including structure fields, like p.Xarrays and slice elements, like perim[0].

Point(1,2).ScaleBy(2) //Compilation error, cannot obtain the address of Poing type literal

If the actual parameter receiver is *Point type, it is legal to call the Point type method in Point.Distance mode. The compiler automatically inserts an implicit * operator.

p := Point{1, 2}
pptr := &p

pptr.Distance(q)
(*pptr).Distance(q)
  • nil is a legal receiver
// IntList 是整形链表
// * IntList 的类型 nil 代表空列表
type IntList struct {
    
    
	Value int
	Tail *IntList
}

// Sum 返回表元素的总和
func (list *IntList) Sum() int {
    
    
	if list == nil {
    
    
		return 0
	}
	return list.Value + list.Tail.Sum()
}

6.3 Compose types through embedded structures

import "image/color"

type Point struct{
    
    X, Y float 64}

type ColoredPoint struct {
    
    
	Point
	Color color.RGBA
}
var cp ColoredPoint
cp.X = 1

Methods of an embedded type Point can be called through a receiver of type ColoredPoint.

red := color.RGBA{
    
    255, 0, 0, 255}
blue := color.RGBA{
    
    0, 0, 255, 255}
var p = ColoredPoint{
    
    Point{
    
    1, 1}, red}
var q = ColoredPoint{
    
    Point{
    
    5, 4}, blue}
p.ScaleBy(2)
p.Distnace(q.Point)

Point's methods are incorporated into the ColorPoint type.

In the Go language, the Point type is not the base class of the ColoredPoint type.

ColoredPoint contains a Point, and it has two additional methods Distance and ScaleBy derived from Point. If you think about the specific implementation, in fact, the embedded field tells the compiler to generate additional wrapper methods to call the methods declared by Point, which is equivalent to the following code.

func (p ColoredPoint) Distance(q Point) float64 {
    
    
	return p.Point.Distance(q)
}

func (p* ColoredPoint) ScaleBy(factor float64) {
    
    
	p.Point.ScaleBy(factor)
}

An anonymous field type can be a pointer to a named type, in which case the fields and methods come indirectly from the pointed object.

Struct types can have multiple anonymous fields. Declare ColoredPoint:

type ColoredPoint struct {
    
    
	Point
	color.RGBA
}

Then the value of this class can have all the methods of Point and all the methods of RGBA, as well as any other methods declared directly in the ColoredPoint type. When the compiler processes a selector (such as p.ScaleBy), it first looks for the directly declared method ScaleBy, and then looks for the method from the embedded field from ColoredPoint. The method here undergoes a promotion; finally, it looks for the method from Point and Search in the method embedded in RGBA. The method here has been improved twice.
If there are two function promotions with the same name at the same level, the compiler will report an error. For example, Point and color.RGBA both have Scaleby functions.

6.4 Method variables and expressions

p.Dsitance can be assigned to a method variable, which is a function that binds the method (Point.Distance) to a receiver p. Functions only need to provide actual parameters and do not need to provide a receiver to be called.

p := Point{
    
    1, 2}
q := Point{
    
    4, 6}
distanceFromP := p.Distance // 方法变量
fmt.Println(distanceFromP(q))

Related to method variables are method expressions. The method expression is written as Tf or (*T).f, where T is the type, which is a function variable. The receiver of the original method is replaced with the first formal parameter of the function, so it can be like the usual Anhui Province South Same call.

package main

import (
	"fmt"
	"math"
)

type Point struct{
    
     X, Y float64 }

func (p Point) Distance(q Point) float64 {
    
    
	return math.Hypot(q.X-p.X, q.Y-p.Y)
}

func (p *Point) ScaleBy(factor float64) {
    
    
	p.X *= factor
	p.Y *= factor
}

func main() {
    
    
	p := Point{
    
    1, 2}
	q := Point{
    
    4, 6}

	distance := Point.Distance // 方法表达式
	fmt.Println(distance(p, q))

	scale := (*Point).ScaleBy
	scale(&p, 2)
	fmt.Println(p)            //{2, 4}
	fmt.Printf("%T\n", scale) // func(*Point, float64)
}

6.5 Example: Bit Vectors

6.6 Packaging

type IntSet struct {
    
    
	words []uint64
}

can be defined as

type IntSet []uint64

Replace s.words with *s when using it.
Although this version of IntSet is basically the same as the previous one, it allows methods in other packages to read and modify the slice. In other words, the expression *s can be used in other packages, and s.words can only be used in the package in which IntSet is defined.

Another conclusion is that the unit of Go language encapsulation is a package rather than a type. Whether code within a function or within a method, fields within a structure type are visible to all code in the same package.

Encapsulation provides three advantages.
First, because the user cannot directly modify the object's variables, no more statements are needed to check the value of the variable.
Second, hiding implementation details can prevent the properties that users rely on from changing, allowing designers to more flexibly change the implementation of the API without breaking compatibility.
Third, prevent users from arbitrarily changing variables inside the object.

Guess you like

Origin blog.csdn.net/houzhizhen/article/details/135404427