Go语言借助方法来实现OOP
Go语言OOP的两个关键是封装和组合

一、方法

  1. 方法是属于某种类型的,方法可以被声明到任意类型,只要不是一个指针或者一个interface。

值类型和引用类型:

(1)值类型包括:基本数据类型int系列、float系列、bool、string、数组和结构体;

(2)引用类型:指针、slice切片、map、管道channel、interface等;

值类型和引用类型的区别: (1)值类型,变量直接存储,内存通常在栈中分配;

(2)引用类型:变量存储的是一个地址,这个地址对应的空间才是真正存储的数据值,内存通常在堆上分配,当没有任何变量引用这个地址时,此地址对应的数据空间就是一个垃圾,由GC来回收;


    type Point struct {
        x, y float64
    }

    //function 
    func Distance(p, q Point) float64 {
        return math.Hypot(q.x-p.x, q.x-p.x)
    }

    //method
    //p为方法的接收器(receiver),接收器的名字建议用类型的第一个字母或第2个word的第一个字母
    func (p Point) Distance(q Point) float64 {
        return math.Hypot(q.x-p.x, q.y-p.y)
    }

    p := Point{1, 2}
    q := Point{4, 6}
    fmt.Println(Distance(p, q)) // "5", function call
    fmt.Println(p.Distance(q)) // "5", method call
    //p.Distance被称为选择器

    //计算线段的长度
    // A Path is a journey connecting the points with straight lines.
    type Path []Point
    // Distance returns the distance traveled along the path.
    func (path Path) Distance() float64 {
        sum := 0.0
        for i := range path {
            if i > 0 {
                sum += path[i-1].Distance(path[i])
            }
        }
        return sum
    }
  1. 基于指针对象的方法

接收器的对象本身占用内存很大时,最好用指针声明方法 如果对象的某个方法的接收器为指针,那么该对象的所有方法都要使用指针做接收器

    func (p *Point) ScaleBy(factor float64) {
        p.X *= factor
        p.Y *= factor
    }

    //调用方法
    1. 
    r := &Point{1, 2}
    r.ScaleBy(2)
    fmt.Println(*r) // "{2, 4}"
    
    2.
    p := Point{1, 2}
    pptr := &p
    pptr.ScaleBy(2)
    fmt.Println(p) // "{2, 4}"

    3. 
    p := Point{1, 2}
    (&p).ScaleBy(2)
    fmt.Println(p) // "{2, 4}"

    //上述2和3可以使用对象直接调用方法,Go会自动用对应的指针去调用方法
    p := Point{1, 2}
    p.ScaleBy(2)
  1. nil 也是合法的接收器类型
    // An IntList is a linked list of integers.
    // A nil *IntList represents the empty list.
    type IntList struct {
        Value int
        Tail *IntList
    }
    // Sum returns the sum of the list elements.
    func (list *IntList) Sum() int {
        if list == nil {
            return 0
        }
        return list.Value + list.Tail.Sum()
    }
  1. 方法值和方法表达式

,选择器会返回一个方法"值"-> 一个将方法(Point.Distance)绑定到特定接收器变量的函数

    p := Point{1, 2}
    q := Point{4, 6}
    distanceFromP := p.Distance // method value
    fmt.Println(distanceFromP(q)) // "5"
    var origin Point // {0, 0}
    fmt.Println(distanceFromP(origin)) // "2.23606797749979", sqrt(5)
    scaleP := p.ScaleBy // method value
    scaleP(2) // p becomes (2, 4)
    scaleP(3) // then (6, 12)
    scaleP(10) // then (60, 120)

二、封装

  1. 定义

一个对象的变量或者方法如果对调用方是不可见的话,一般就被定义为“封装”。封装有时候也 被叫做信息隐藏。

  1. 优点
(1) 调用方不能直接修改对象的变量值
(2) 隐藏实现的细节
(3) 阻止了外部调用方对对象内部的值任意地进行修改
  1. 封装并不总是理想的。

三、总结

方法只是OOP编程里的半边天,另一半是接口。