Golang: Language: Struct

 27th April 2021 at 6:55am

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>