1, Basis of structural variable method
Structural variables not only have their own attributes, but also have their own methods. For example, a person not only has a name and age, but also has some behaviors. These behaviors can be understood as methods in structural variables. The methods in Golang are bound to specific data types, so it's not just the time structure that has its own methods.
(1) Quick start
1. Method declaration
func(receiver type) methodName(parameter list) (Return value list){ Method body return Return value }
- Parameter list: indicates method input
- receiver type: indicates that the method is bound to the type, or the method acts on the type
- receiver type: type can be a structure or other user-defined types
- receiver: is an instance of type
- Return value list: indicates the returned value, which can be multiple
- Method body: represents a block of code to implement a function
- The return statement is not required
For example:
package main import "fmt" type User struct { Name string Age int } func (user User) getUser() { fmt.Println(user.Name, user.Age) } func main() { var user User user.Name = "bily" user.getUser() }
- Func (User) getUser() {} represents the method of the User structure. The method name is getUser
- (a) reflect getUser method and User type binding
- The getUser method can only be called through the User instance
- The user instance in the main function is not the same as the user instance passed in by the getUser method. The method is copied, and the structure is value transfer
2. Instance
package main import "fmt" type CalSum struct { n1 int n2 int } // Structure calls method, which can have input parameter and return value func (cal CalSum) getSum() int { res := cal.n1 + cal.n2 return res } func main() { // Generate a structure variable cal := CalSum{ 1, 2, } // Call method res := cal.getSum() fmt.Println(res) }
(2) In depth understanding of structural variable methods
1. Method calling mechanism
Methods are similar to functions, but the biggest difference is that the method will pass the caller to the method as a parameter. For example, Cal will be passed to the getSum method as a parameter in the above figure. It should be noted that if it is a value type, the value will be copied, and if it is a pointer type, the reference will be passed, which is related to the formal parameter type.
The default is value type transfer, which means that the structure variables in the method are copied from the main function, so the efficiency is low. In order to improve the efficiency, reference transfer can be carried out.
package main import "fmt" type CalSum struct { n1 int n2 int } // Structure calls method, which can have input parameter and return value func (cal *CalSum) getSum() int { res := cal.n1 + cal.n2 return res } func main() { // Generate a structure variable cal := CalSum{ 1, 2, } /* Call the method. Because the formal parameter of the method is a pointer type, it should be called by the address of the structure variable */ res := (&cal).getSum() // .The operation priority of is high, so(&cal)Parentheses are required fmt.Println(res) // 3 /* But the compiler is optimized at the bottom, so (& CAL) Getsum () can be written as cal getSum() */ res1 := cal.getSum() fmt.Println(res1) /* At this time, the structure variable in main is the same as the structure variable passed in the method, and the existing form in memory is also different from the value transfer */ }
2. The method is not unique to the structure
Methods are not unique to struct types. For example, int and float series types can have methods:
package main import "fmt" type integer int // integer Type method func (i *integer) change() { *i = *i + 5 } func main() { var i integer = 5 i.change() fmt.Println(i) // 10 }
3. Differences between methods and functions
- The function is called by function name (argument list) and the method is called by variable Method name (argument list)
- For ordinary functions, the receiver is of value type, and data of pointer type cannot be passed, and vice versa
- For methods, when the receiver is a value type, you can directly call the method with a pointer type variable, and vice versa
- The real decision between the time value copy and the time address copy depends on the type with which this method is bound. If the time value type is (user User), it is the value copy, and if it is (user *User), it is the address copy
2, Factory mode
(1) Lead to problems
If there is a model package with a structure variable:
package model // Define a structure type User struct { Name string Age int }
If you create an instance of the User structure in other packages, such as the main package, there is no problem at this time, because the first letter of the User structure is uppercase, but if the User is lowercase, it is a private variable, which can be accessed in this package. What if you solve the problem of accessing private variables across packages? This requires the use of factory mode, which is simply to determine the way a public method provides an external interface.
(2) Solution
1. Normal scheme
- User.go
package model // Define a structure type User struct { Name string Age int }
- main.go
package main import ( "fmt" "go_tutorial/day12/factorMode/model" ) func main() { user := model.User{Name: "lily", Age: 20} fmt.Println(user) }
- directory structure
├─factorMode
├─main
│ main.go
│
└─model
user.go
User It is OK that the structure variables in go are capitalized, but if they are lowercase, there will be a problem that private variables cannot cross package. In this case, the factory mode is used.
2. Factory mode solves the cross package problem of private variables
- user.go
package model // Define a private node type user struct { Name string Age int } // Factory method that the package can call func NewUser(name string, age int) *user { return &user{ Name: name, Age: age, } }
- main.go
package main import ( "fmt" "go_tutorial/day12/factoryMode01/model" ) func main() { user := model.NewUser("lily", 20) fmt.Println(*user) // {lily 20} fmt.Println(user.Name, user.Age) // lily 20 }
- directory structure
├─factorMode
├─main
│ main.go
│
└─model
user.go
3. Factory mode solves the problem of cross package of private fields
The above is the cross package problem of private structure variables, but if it is a private variable with lowercase initial letters in the structure, how to solve it?
- user.go
... // Private field name Factory method func GetName(u *user) string { return u.name } ...
- main.go
... func main() { user := model.NewUser("lily", 20) fmt.Println(model.GetName(user)) //lily }
3, Example drill
Create a Box structure in which:
- Declare that the three fields represent the length, width and height of the cube respectively, and obtain them from the terminal
- Declare a method to get the cube volume
- Create a Box structure variable to print the volume of a given size cube
package main import "fmt" type Cell struct { length float64 width float64 height float64 } func (cell *Cell) GetVolume() float64 { return cell.length * cell.width * cell.height } func main() { // Create a cube structure variable var cell Cell // Assign a value to each field fmt.Print("Please enter the length of the cube:") fmt.Scanln(&cell.length) fmt.Print("Please enter the width of the cube:") fmt.Scanln(&cell.width) fmt.Print("Please enter the height of the cube:") fmt.Scanln(&cell.height) // Method of calling structure variable res := cell.GetVolume() fmt.Println(res) }