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) } }