方法和接口
正文
go 沒有類,但是能定義結構的成員函數:
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
}
同時不想C++那樣有頭文件的概念,必須在一個文件內部定義和實現這個結構體的全部成員方法。
這種感覺就是像是一個結構體會有一個成員方法表,每當出現func (t Type) Foo()
這種定義函數的時候直接在Type的方法表內部插入這個Foo
函數。
go裏面也特別的區別了值 和指針, 如果v.Foo()
那麼不會改變v
本身內部的值,而是對一個拷貝的值操作,但是定義是:func (t *Type) Foo()
的時候,v.FOO
的操作不是對拷貝的v操作而是v
本身。
指針
var v Vertex
v.Scale(5) // OK
p := &v
p.Scale(10) // OK
這裏我們看到了一個非常混淆的用法,在c++的寫法中,我們會明確的感知到代碼中值變量和指針變量:
Vertex v;
v.Scale(5) // OK
Vertex* p = &v
p->Scale(10) // OK
看到了嗎?->
和.
。go語言可能爲了簡潔是把->
去掉了,但是我覺得這並不是一個很好的設計,因爲代碼閱讀的時候你會一眼看出來誰是值變量,誰是指針變量。
這裏go舉了例子:
// 當方法是外部方法的時候,
// 結構體的指針和值變量在代碼語法上是不一致的
var v Vertex
fmt.Println(AbsFunc(v)) // OK
fmt.Println(AbsFunc(&v)) // 編譯錯誤!
// 當方法是成員變量的時候,
// 結構體的指針和值變量在代碼語法上是一致的。
var v Vertex
fmt.Println(v.Abs()) // OK
p := &v
fmt.Println(p.Abs()) // OK
也就是說,內質爲成員方法是更加方便的。當然,調試起來有的時候忘記了爲啥變量改變就很麻煩了。
不要爲了方便而濫加成員變量,記住職責單一。
這裏我想知道,go語言是如何做const &
的因爲有很多時候爲了避免開銷而是用引用,但是又想要避免值得改變。