Go 中的 Struct——无类实现面向对象编程
星期五, 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里面命名都应该是统一规定的,它要求你使用驼峰式的命名,是否使用大小写开头则要看是否需要导出。
评论已关闭