Go language Bible - Chapter 6 methods - 6.4 method values and method expressions

Chapter 6 methods

Since the 1990s, object-oriented programming (OOP) has become a programming paradigm that dominates the engineering and educational circles. Therefore, almost all large-scale applied languages include OOP support, and Go language is no exception

In fact, OOP is not clearly defined, but the general meaning is that an object is actually a simple value or a variable. This object will contain some methods, while a method is a function associated with a special type. An object-oriented program will use methods to express its properties and corresponding operations, In this way, users who use this object do not need to operate the object directly, but do these things with the help of methods

In earlier chapters, we have actually used some methods provided by the standard library, such as the second method of time.Duration

const day = 24*time.Hour
fmt.Println(day.Seconds())//86400

In Section 2.5, we defined a method, a String method of Celsius type

func (c Celsius) String() string{
   return fmt.Sprintf("%g˚C",c)
}

In this chapter, the first aspect of OOP programming, we will show how to effectively define and use methods. We will cover the two key points of OOP programming, encapsulation and combination

6.4 method values and method expressions

We often choose a method and execute it in the same expression, such as the common form of P. detacne (). In fact, it is OK to divide it into two parts. p.Distance is called a selector. The selector will return a method "value" - > a function that binds the method (Point.Distance) to a specific receiver variable. This function can be called without specifying the receiver, that is, it is not allowed to specify the receiver when calling, just pass in the parameters:

p:=Point{1,2}
q:=Point{4,6}

distanceFromP := p.Distance //First step
fmt.Println(distanceFromP(q))//Step 2

var origin Point
fmt.Println(distanceFromP(origin))

scalP := p.ScaleBy
scalP(2)
scalP(3)
scalP(10)

If the API of a package needs a function value and the caller wants to operate a method bound to an object, "method value" is very useful. For example, time.Func is used to execute a function after the specified delay time, and this function operates a Rocket object r

type Rocket struct{/* ... */}
func (r *Rocket)lunch(){
r := new(Rocket)
time.After(10*time.Second,func(){r.lunch()})

It can be shorter if you directly pass the method "value" into AfterFunc

time.AfterFunc(10*time.Second,r.Launh)

Note: the anonymous function above is omitted

Also related to the method "value" is the method expression: compared with calling an ordinary function, when calling a method, we must use the selector (p.Distance) syntax to specify the receiver of the method

When t is a type, the method expression may be written as T.f or (* t). F, which will return a function "value". This function will use its first parameter as a receiver, so it can be called without writing a selector

p:=Point{1,2}
q:=Point{4,6}

distance := Point.Distance
fmt.Println(distance(q,p))//5 seems to change back to calling the function
fmt.Printf("%T\n",distance)//func(main.Point, main.Point) float64

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

When you decide which function of the same type to call according to a variable, the method expression is very useful. You can absolutely choose to call methods with different receivers. In the following example, the variable op represents the Add or Sub method of Point type, and the Path.TranslateBy method will call the corresponding method for each Point in its Path array

type Point struct {X,Y float64}

func (p Point) Add(q Point) Point{return Point{p.X+q.X,p.Y+q.Y}}
func (p Point) Sub(q Point) Point{return Point{p.X-q.X,p.Y-q.Y}}

type Path []Point

func (path Path) TranslateBy (offset Point,add bool) {
   var op func(p,q Point) Point
   if add{
      op = Point.Add
   }else {
      op = Point.Sub
   }
   for i := range path{
      path[i] = op(path[i],offset)
   }
}

Tags: Go

Posted on Thu, 11 Nov 2021 20:16:18 -0500 by anto