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
复制代码
一个结构体只能嵌入一个同类型的成员,无须担忧结构体重名和错误赋值的状况,编译器在发现可能的赋值歧义时会报错。