Go 中没有 class,只有 struct。struct 的字面值是:
struct {
X, Y float64
}
你需要用 type
给它起个名字:
type Vertex struct {
X, Y float64
}
声明及初始化一个 struct:
//// 使用 struct 字面值
// X, Y 为默认的 0
var s1 struct { X, Y float64 }
// 给 X, Y 赋初值
var s2 struct { X, Y float64 } = struct { X, Y float64 } {1, 2}
// 自动推导类型(省掉类型定义)
var s3 = struct { X, Y float64 } {1, 2}
// 省掉 var
s4 := struct { X, Y float64 } {1, 2}
//// 使用 type 定义的类型能简化书写
var v1 Vertex;
var v2 Vertex = Vertex{1, 2}
var v3 = Vertex{1, 2}
v4 := Vertex{1, 2}
struct 是一种值类型,它的默认值不是 nil
,而是其中各属性的 zero-value 所组成的一个 struct。
定义 struct 的方法(method)是带上一个 receiver 参数(v Vertex
):
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
// 等同于
func Abs(v Vertex) float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
Receiver 参数可以是值(v Vertex
)也可以是指针(v *Vertex
)。当是值的时候,会复制一次 Vertex 的值;当是指针时,传的是引用。因此如果你要在方法中修改 struct 的属性,要用指针(大部分情况下都用指针,避免拷贝):
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 (v Vertex) Scale1(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func (v *Vertex) Scale2(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v1 := Vertex{3, 4}
v1.Scale1(10)
fmt.Println(v.Abs()) // 5,因为 Scale1 不修改 v1 本身的属性
v1.Scale2(10) // 等同于 (&v1).Scale2(10),Go 为了方便隐式做了转换
fmt.Println(v.Abs()) // 50,因为 Scale2 修改 v1 本身的属性
v2 := &Vertex{3, 4} // 等同于 (*v2).Scale2(10),Go 为了方便隐式做了转换
v2.Scale1(10) // 仍不改变 v2 本身的属性
v2.Scale2(10) // 会改变 v2 本身的属性
}
当你定义了一个指针 receiver 的函数时,即使它的 receiver 为 nil,也一样可以调用(这点与其他语言非常不一样):
func (v *Vertex) say() {
if v == nil {
fmt.Println("<nil>")
} else {
fmt.Println("hello")
}
}
func main() {
var v1 *Vertex
v1.say()
}
<nil>