Go 語言中同時有函數和方法。方法就是一個包含了接收者的函數,接收者能夠是命名類型或者結構體類型的一個值或者是一個指針。全部給定類型的方法屬於該類型的方法集。node
在 Go 中,(接收者)類型關聯的方法不寫在類型結構裏面,就像類那樣;耦合更加寬鬆;類型和方法之間的關聯由接收者來創建。 方法沒有和數據定義(結構體)混在一塊兒:它們是正交的類型;表示(數據)和行爲(方法)是獨立的。bash
語法格式以下:函數
func (variable_receiver_name receiver_type) function_name([parameter list]) [return_type]{
/* 函數體*/
}
複製代碼
package main
import (
"fmt"
)
// 定義結構體
type Circle struct {
radius float64
}
func main() {
var c1 Circle
c1.radius = 10.00
fmt.Println("圓的面積 = ", c1.getArea())
}
// 該 method 屬於 Circle 類型對象中的方法
func (c Circle) getArea() float64 {
// c.radius 即爲 Circle 類型對象中的屬性
return 3.14 * c.radius * c.radius
}
// 執行結果爲:的面積 = 314
複製代碼
接收者有兩種,一種是值接收者,一種是指針接收者。顧名思義,值接收者,是接收者的類型是一個值,是一個副本,方法內部沒法對其真正的接收者作更改;指針接收者,接收者的類型是一個指針,是接收者的引用,對這個引用的修改之間影響真正的接收者。像上面同樣定義方法,將 user 改爲 *user 就是指針接收者。ui
struct的方法調用this
方法調用至關於普通函數調用的語法糖。Value方法的調用m.Value()等價於func Value(m M) 即把對象實例m做爲函數調用的第一個實參壓棧,這時m稱爲receiver。經過實例或實例的指針其實均可以調用全部方法,區別是複製給函數的receiver不一樣。spa
以下,經過實例m調用Value時,以及經過指針p調用Value時,receiver是m和*p,即複製的是m實例自己。所以receiver是m實例的副本,他們地址不一樣。經過實例m調用Pointer時,以及經過指針p調用Pointer時,複製的是都是&m和p,即複製的都是指向m的指針,返回的都是m實例的地址。指針
type M struct {
a int
}
func (m M) Value() string {return fmt.Sprintf("Value: %p\n", &m)}
func (m *M) Pointer() string {return fmt.Sprintf("Pointer: %p\n", m)}
var m M
p := &m // p is address of m 0x2101ef018
m.Value() // value(m) return 0x2101ef028
m.Pointer() // value(&m) return 0x2101ef018
p.Value() // value(*p) return 0x2101ef030
p.Pointer() // value(p) return 0x2101ef018
複製代碼
當接受者變量自己比較大時,能夠用其指針而不是對象來聲明方法,這樣能夠節省內存空間的佔用。code
package main
import (
"fmt"
"math"
)
// 方法聲明
type Point struct {
X,Y float64
}
func (p *Point) Distance(q *Point) float64 {
return math.Hypot(q.X - p.X, q.Y - p.Y)
}
func main() {
p := &Point{3,5}
fmt.Println(p.Distance(&Point{5, 6}))
}
// 執行結果爲:2.23606797749979
複製代碼
package main
import "fmt"
// 將nil做爲接收器
type IntNode struct {
Value int
Next *IntNode
}
func (node *IntNode) Sum() int {
if node == nil {
return 0
}
return node.Value + node.Next.Sum()
}
func main() {
node1 := IntNode{30, nil}
node2 := IntNode{12, nil}
node3 := IntNode{43, nil}
node1.Next = &node2
node2.Next = &node3
fmt.Println(node1.Sum())
fmt.Println(node2.Sum())
node := &IntNode{3, nil}
node = nil
fmt.Println(node.Sum())
}
// 執行結果爲:
// 85
// 55
// 0
複製代碼
示例:對象
package main
import (
"fmt"
)
// 基礎顏色
type BasicColor struct {
// 紅、綠、藍三種顏色份量
R, G, B float32
}
// 完整顏色定義
type Color struct {
// 將基本顏色做爲成員
BasicColor
// 透明度
Alpha float32
}
func main() {
// 設置基本顏色份量
var c Color
c.R = 1
c.G = 1
c.B = 0
// 設置透明度
c.Alpha = 1
// 顯示整個結構體內容
fmt.Printf("%+v", c)
}
複製代碼
代碼輸出以下: {Basic:{R:1 G:1 B:0} Alpha:1}內存
Go語言的結構體內嵌特性:
var c Color
c.BasicColor.R = 1
c.BasicColor.G = 1
c.BasicColor.B = 0
複製代碼
一個結構體只能嵌入一個同類型的成員,無須擔憂結構體重名和錯誤賦值的狀況,編譯器在發現可能的賦值歧義時會報錯。