golang方法詳解
Go 語言 類型方法是一種對類型行為的封裝 。Go 語言的方法非常純粹, 可以看作特殊類型的函數,其顯式地將對象實例或指針作為函數的第一個參數,並且參數可以自己指定,而不強制要求一定是 this或self。 這個對象實例或指針稱為方法的接收者 (reciever)。
方法聲明
為命名類型定義方法的語法格式如下:
// 類型方法接收者是值類型
func (t TypeName) MethodName (ParamList ) (Returnlist) {
// method body
}
// 類型方法接收者是指針
func (t *TypeName) MethodName (ParamList) (Returnlist) {
// method body
}
說明:
- t 是接收者,可以自由指定名稱。
- TypeName 為命名類型的類型名。
- MethodName 為方法名,是 個自定義標識符。
- ParamList 是形參列表。
- ReturnList 是返回值列表。
Go語言的類型型方法本質上就是一個函數,沒有使用隱式的指針,這是Go的優點,簡單明了。我們可以將類型的方法改寫成常規的函數。示例如下:
// 類型方法接收者是值類型
func TypName MethodName(t TypeName , otherParamList) (Returnlist) {
//method body
}
// 類型方法接收者是指針
func TypName MethodName (t *TypeName , otherParamList) (Returnlist) {
//method body
}
// 示例
type SliceInt []int
// 定義一個 SliceInt的方法,實現累加切邊成員的功能
func (s SliceInt) Sum() int {
sum := 0
for _, i := range s{
sum += i
}
return sum
}
// 這個函數和上面的方法等價
func SliceInt_Sum(s SliceInt) int {
sum := 0
for _, i := range s {
sum += i
}
return sum
}
var s SliceInt = [] int {1, 2, ,3, 4}
// 使用方法訪問
s.Sum()
// 直接訪問
SliceInt_Sum(s)
類型方法有如下特點
(1)可以為命名類型增加方法(除了介面),非命名類型不能自定義方法。 (非命令類型指型由預聲明類型、關鍵字和操作符組合而成的類型,例如數組、切邊、通道、指針、函數等)
比如不能為 [ ] int 類型增加方法,因為 [ ] int 是非命名類型。介面類型本身就是一個方法的簽名集合,所以不能為其增加具體的實現方法。
(2)為類型增加方法有一個限制,就是方法的定義必須和類型的定義在同一個包中。
不能再為 int、bool 等預聲明類型增加方法,因為它們是命名類型,但它們是 Go 語言內置的預聲明類型,作用域是全局的,為這些類型新增的方法是在某個包中,這與第(2)條規則衝突,所以Go編譯器拒絕為int增加方法。
(3)方法的命名空間的可見性和變數一樣,大寫開頭的方法可以在包外被訪問,否則只能 在包內可見。
(4)使用 type 定義的自定義類型是一個新類型,新類型不能調用原有類型的方法,但是底層類型支援的運算可以被新類型繼承。
type Map map[string)string
func (m Map) Print() {
// 類型支援的 range 運算 新類型可用
for _, key := range m{
fmt.Println(key)
}
}
type MyInt int
func main() {
var a MyInt = 10
var b MyInt = 10
// int 類型支援的加減乘除運算,新類型同樣可用
c := a + b
d := a * b
fmt.Println("%d\n", c)
fmt.Println("%d\n", d)
}
方法調用
總結一下方法調用,類型方法的一般調用方式:
TypeinstanceName.MethodName(ParamList)
-
TypeinstanceName: 類型實例名或指向實例的指針變數名;
-
MethodName: 類型方法名;
-
ParamList: 方法實參。
示例:
type T struct {
a int
}
func (t T) Get() int {
return t.a
}
func (t *T) Set (i int) {
t. a = i
}
var t = &T{}
// 普通方法調用
t.Set(2)
// 普通方法調用
t.Get( )
方法值( method value )
變數x的靜態類型是T, M是類型T的一個方法, x.T被稱為方法值(method value), x.T是一個函數類型變數,可以賦值給其他變數 。例如:
f : = x.M f (args .. . )
等價於
x.M(args ... )
方法值(method value)其實是一個帶有閉包的函數變數,其底層實現原理和帶有閉包的匿名函數類似,接收值被隱式地綁定到方法值(method value)的閉包環境中。後續調用不需要再顯式地傳遞接收者。例如:
type T struct {
a int
}
func (t T) Get() int {
return t.a
}
func (t *T) Set (i int ) {
t.a = i
}
func (t *T) Print () {
fmt.Printf ("%p, %v, %d \n", t, t, t.a)
}
var t =&T{}
//method value
f := t.Set
// 方法值調用
f(2)
t.Print() //結果為 0xc4200140b8, &{2}, 2
//方法值調用, 接受值保存了方法值的環境
f(3)
t.Print() //結果為 0xc4200140b8, &{3}, 3

