Go學習(10):方法
阿新 • • 發佈:2018-11-28
一.方法
1.1 什麼是方法
Go 語言中同時有函式和方法。一個方法就是一個包含了接受者的函式,接受者可以是命名型別或者結構體型別的一個值或者是一個指標。所有給定型別的方法屬於該型別的方法集
方法只是一個函式,它帶有一個特殊的接收器型別,它是在func關鍵字和方法名之間編寫的。接收器可以是struct型別或非struct型別。接收方可以在方法內部訪問。
1.2 方法的語法
定義方法的語法
func (t Type) methodName(parameter list) {
}
例項程式碼:
package main
import (
"fmt"
)
type Employee struct {
name string
salary int
currency string
}
/*
displaySalary() method has Employee as the receiver type
*/
func (e Employee) displaySalary() {
fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}
func main() {
emp1 := Employee {
name: "Sam Adolf",
salary: 5000,
currency: "$",
}
emp1.displaySalary() //Calling displaySalary() method of Employee type
}
可以定義相同的方法名
示例程式碼:
package main
import (
"fmt"
"math"
)
type Rectangle struct {
width, height float64
}
type Circle struct {
radius float64
}
func (r Rectangle) area() float64 {
return r.width * r.height
}
//該 method 屬於 Circle 型別物件中的方法
func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
c1 := Circle{10}
c2 := Circle{25}
fmt.Println("Area of r1 is: ", r1.area())
fmt.Println("Area of r2 is: ", r2.area())
fmt.Println("Area of c1 is: ", c1.area())
fmt.Println("Area of c2 is: ", c2.area())
}
執行結果
Area of r1 is: 24
Area of r2 is: 36
Area of c1 is: 314.1592653589793
Area of c2 is: 1963.4954084936207
- 雖然method的名字一模一樣,但是如果接收者不一樣,那麼method就不一樣
- method裡面可以訪問接收者的欄位
- 呼叫method通過.訪問,就像struct裡面訪問欄位一樣
1.3 方法和函式
既然我們已經有了函式,為什麼還要使用方法?
示例程式碼:
package main
import (
"fmt"
)
type Employee struct {
name string
salary int
currency string
}
/*
displaySalary() method converted to function with Employee as parameter
*/
func displaySalary(e Employee) {
fmt.Printf("Salary of %s is %s%d", e.name, e.currency, e.salary)
}
func main() {
emp1 := Employee{
name: "Sam Adolf",
salary: 5000,
currency: "$",
}
displaySalary(emp1)
}
在上面的程式中,displaySalary方法被轉換為一個函式,而Employee struct作為引數傳遞給它。這個程式也產生了相同的輸出:Salary of Sam Adolf is $5000.。
為什麼我們可以用函式來寫相同的程式呢?有以下幾個原因
- Go不是一種純粹面向物件的程式語言,它不支援類。因此,型別的方法是一種實現類似於類的行為的方法。
- 相同名稱的方法可以在不同的型別上定義,而具有相同名稱的函式是不允許的。假設我們有一個正方形和圓形的結構。可以在正方形和圓形上定義一個名為Area的方法。這是在下面的程式中完成的。
1.4 變數作用域
作用域為已宣告識別符號所表示的常量、型別、變數、函式或包在原始碼中的作用範圍。
Go 語言中變數可以在三個地方宣告:
- 函式內定義的變數稱為區域性變數
- 函式外定義的變數稱為全域性變數
- 函式定義中的變數稱為形式引數
區域性變數
在函式體內宣告的變數稱之為區域性變數,它們的作用域只在函式體內,引數和返回值變數也是區域性變數。
全域性變數
在函式體外宣告的變數稱之為全域性變數,首字母大寫全域性變數可以在整個包甚至外部包(被匯出後)使用。
package main
import "fmt"
/* 宣告全域性變數 */
var g int
func main() {
/* 宣告區域性變數 */
var a, b int
/* 初始化引數 */
a = 10
b = 20
g = a + b
fmt.Printf("結果: a = %d, b = %d and g = %d\n", a, b, g)
}
結果
結果: a = 10, b = 20 and g = 30
形式引數
形式引數會作為函式的區域性變數來使用
指標作為接收者
若不是以指標作為接收者,實際只是獲取了一個copy,而不能真正改變接收者的中的資料
func (b *Box) SetColor(c Color) {
b.color = c
}
示例程式碼
package main
import (
"fmt"
)
type Rectangle struct {
width, height int
}
func (r *Rectangle) setVal() {
r.height = 20
}
func main() {
p := Rectangle{1, 2}
s := p
p.setVal()
fmt.Println(p.height, s.height)
}
結果
20 2
如果沒有那個*,則值就是2 2
1.5 method繼承
method是可以繼承的,如果匿名欄位實現了一個method,那麼包含這個匿名欄位的struct也能呼叫該method
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human //匿名欄位
school string
}
type Employee struct {
Human //匿名欄位
company string
}
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}
執行結果:
Hi, I am Mark you can call me on 222-222-YYYY
Hi, I am Sam you can call me on 111-888-XXXX
1.6 method重寫
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human //匿名欄位
school string
}
type Employee struct {
Human //匿名欄位
company string
}
//Human定義method
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
//Employee的method重寫Human的method
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}
執行結果:
Hi, I am Mark you can call me on 222-222-YYYY
Hi, I am Sam, I work at Golang Inc. Call me on 111-888-XXXX
- 方法是可以繼承和重寫的
- 存在繼承關係時,按照就近原則,進行呼叫