1.1 method statement
The declaration of the method is similar to that of a normal function, except that a parameter is added before the function name. This parameter binds this method to the type corresponding to this parameter
import (
"fmt"
)
type Point struct {
x, y int
}
func fun() {
fmt.Println("I'm a normal fun")
}
func (p Point) fun() { //The additional parameter p is called the receiver of the method.
fmt.Println("I'm a way")
}
func main() {
p := Point{
x: 1,
y: 2,
}
fun()
p.fun() //Method
}
//Program output: I am a normal fun
//I'm a way
The above declaration of the fun() function does not conflict. The first is a package level function. The second is the method of type Point.
1.2 method of pointer receiver
Because the main function copies an 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 must use a pointer to pass the address of the variable.
package main
import(
"fmt"
)
type Point struct {
a int
b int
}
func (p *Point) fun(val int) {
p.a *= val
p.b *= val
}
func main() {
p := Point{
a: 5,
b: 10,
}
(&p).fun(2)
fmt.Println(p)
}
//Program output:{10,20}
Note: a named type (Point) and a pointer to its people (* Point) are the only types that can appear at the receiver declaration. Furthermore, to prevent confusion, method declarations of types that themselves are pointers are not allowed:
type P *int
func (P) f(){ //Compilation error: illegal recipient type
/* ... */
}
nil is a legal receiver
//Intlist is a plastic linked list
//*Intlist's type nil represents an empty list
type Intlist struct{
value int
tail *Intlist
}
// Sum returns the sum of linked list elements
func (list *Intlist) sum() int{
if nil == list{
return 0
}
return list.value + list.tail.sum()
}
//Note: when defining a type to allow nil as the receiver, it should be indicated in the document annotation
1.3 type of embedded composition through structure
package main
import (
"fmt"
)
type Point struct {
x int
y int
}
type P_point struct {
Point
z int
}
func (p Point) fun1() {
fmt.Println("I am point Method")
}
func (p P_point) fun1() {
fmt.Println("I am P_point Method")
}
func main() {
var p Point
var P_p P_point
p.fun1()
P_p.Point.fun1()
P_p.fun1()
}
//Output result: I am the method of point
//I'm the point method
//I'm P point's method
1.4 method variables and expressions
Usually we use and call methods in the same expression, just like in p.Distance(), but it's OK to separate the two operations.
p := point{1,2}
q := point{2,3}
fun := p.Distance //Method variables
fun() //It can be executed. Same as function
1.5 encapsulation of methods (sometimes called data hiding)
If a variable or method cannot be accessed through an object, this is called an encapsulated variable or method. There is only one way to control the visibility of naming in GO language: when defining, identifiers with capitals can be exported from packages, otherwise they cannot be exported. The same mechanism applies to methods in fields and types within a structure. The conclusion is that to encapsulate an object, you must use a structure.