星期五, 12/28/2012 - 16:22 — matrixstack

Go是非面向对象的,而是面向过程的,但是在当今程序开发的世界里,使用最为广泛的还是面向对象编程,这或许会让你感觉Go作为一个新生的语言最应该有的一面却没有被支持,但是其实它只是用了自己的方法,在本文里,我将介绍在Go里面,如何实现面向对象(Go提供了面向对象所提供的一切,或许提供得更多)。

如果你一直都是一个“类”用户,那么转到Go的“面向对象”上来,可能还需要一些观念上的转变,这或许很难,但是一旦你转变过来了,你就会发现,Go的方式有多么的强大了。

在了解Go的面向对象之前,一定要在心里面知道:Go是没有类的,这是你进入Go的面向对象世界的第一步,也是最重要的一步;另一个你知道知道的是:Go不是面向对象的,只是他的实现类似于面向对象,我们来看一个简单的示例,它能说明一切:

Java代码:

class House {
    public String getHouseName() { // 方法定义在类里面
        // 实现
    }
}

Go 代码:

type House struct { }
func (h House) GetHouseName() string {} //方法被定义在 Struct 外,但是却作用于 House

现在让我们来学习一下如何创建 Struct 以及如何通过它实现“面向对象”,一个 Struct 通过关键字 type 与 struct 定义:

type my_struct_name struct { }
type Rectangle struct { }
type Vehicle struct { }
type VehicleCar struct { }

上面的所有定义都是合法的,但是下面这样是不合法的:

type Hash# struct { } // 名称不允许包含特殊字符
type 0Struct struct { } // 名称不允许以数字开始

当然了,Struct 还能存储其它数据,所以,在这方面它类似于 Class,可以用来定义真实世界中存在的实体:

type mystruct struct {
    i int
    j int
    s string
}

type Rectangle struct {
    length, width int //你可以在一行中通过逗号分割的方式创建多个同类型的项目
    area float64
}

下面这个示例展示了一个 Struct 的实际应用:

package main
import "fmt"
// 定义 Rectangle 结构
type Rectangle struct {
    length, width int
}
func main() {
    r := Rectangle{}
    fmt.Println("默认的长方形是:", r) // 打印出默认的 Rectangle 的归零值
}

输出为:

默认的长方形是: {0 0}

这里有一个重要的需要注意的事情是:struct中的变量的值都是归零的,也就是说,int 类型的值将为 0,string 类型的值将为空字符串等等,所以,每一个你自己定义的Struct 也都是有一个属于其自己的归堆值的。下面这个示例中,我将展示另一种方式初始化 Struct——在创建它的时候就指定初始值:

package main
import "fmt"
type Rectangle struct {
    length, width int
    name string
}
func main() {
    r1 := Rectangle{2, 1, "First Rectangle"}
    fmt.Println("第一个长方形 r1 为:", r1)
    r2 := Rectangle{width: 3, name: "Second Rectangle", length: 4}
    fmt.Println("第二个长方形 r2 为:", r2)
    pr := new (Rectangle) // 获取一个指向一个新的长方形的指针
    (*pr).width = 6 // 设置 pr 的宽为 6
    pr.length = 8 // 与上面是同样的效果,看这里是没有 -> 符号的
    pr.name = "指针长方形"
    fmt.Println("指针长方形是:", pr)
}

输出为:

第一个长方形 r1 为: {2 1 First Rectangle}
第二个长方形 r2 为: {4 3 Second Rectangle}
指针长方形是: &{8 6 指针长方形}

这里需要注意的事情是:

  • 你可以只将值按 struct 定义时的顺序赋给它的成员,但是需要放在大括号里面,并且每一个值需要使用逗号分开;
  • 如果你给定值的时候还提供了名称,那么就不受顺序的限制;
  • 你可以通过 new 获取到一个新创建的 struct 的指针;
  • 这样的一个指针可以不需要 *操作符;
  • Go默认提供根据Struct的值转换成为字符打印的功能

封装以及 Struct 及其变量的访问

其它的编程语言使用一些特别的关键字(比如 public、private、package‘protected等)定义类中不同的属性与变量的可访问性,当我在使用Go之前,我认为所有的这些都是言存在的,但是之后,我发现,原来实现变量与属性的访问控制可以如此简单:

type notExported struct { // 以小写字母开头命名的struct只能在同一个包内调用,我们称这为不导出
}
type Exported { // 大写开头则可导出,也就是任何包都可以访问
    notExportedVariable int // 小写字母开头不允许包外访问
    ExportedVariable int // 大写字母开头则允许包外访问
    s string // 不导出
    S string // 导出
}

所以,你应该明白,在Go里面命名都应该是统一规定的,它要求你使用驼峰式的命名,是否使用大小写开头则要看是否需要导出。

标签: none

评论已关闭