Go 面向对象编程
Go 并不是完全面向对象的编程语言。Go 官网的 FAQ 回答了 Go 是否是面向对象语言,摘录如下。
可以说是,也可以说不是。虽然 Go 有类型和方法,支持面向对象的编程风格,但却没有类型的层次结构。Go 中的“接口”概念提供了一种不同的方法,我们认为它易于使用,也更为普遍。Go 也可以将结构体嵌套使用,这与子类化(Subclassing)类似,但并不完全相同。此外,Go 提供的特性比 C++ 或 Java 更为通用:子类可以由任何类型的数据来定义,甚至是内建类型(如简单的“未装箱的”整型)。这在结构体(类)中没有受到限制。
结构体替代类
Go 不支持类,而是提供了结构体。结构体中可以添加属性和方法。这样可以将数据和操作数据的方法绑定在一起,实现与类相似的效果。
文件结构:
workspacepath -> oop -> employee -> employee.go
workspacepath -> oop -> main.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //employee.go文件<br>package employee import ( "fmt" ) type Employee struct { FirstName string LastName string TotalLeaves int LeavesTaken int } func (e Employee) LeavesRemaining() { fmt.Printf( "%s %s has %d leaves remaining" , e.FirstName, e.LastName, (e.TotalLeaves - e.LeavesTaken)) } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | //main.go文件<br>package main import "oop/employee" func main() { e := employee.Employee { FirstName: "Sam" , LastName: "Adolf" , TotalLeaves: 30, LeavesTaken: 20, } e.LeavesRemaining() } |
1.Go 并不支持构造器。如果某类型的零值不可用,需要程序员来隐藏该类型,避免从其他包直接访问。程序员应该提供一种名为 NewT(parameters)
的 函数,按照要求来初始化 T
类型的变量。
2.应该让 Employee
结构体不可引用,修改 Employee为employee,这样别的文件就不能引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //employee.go文件<br>package employee import ( "fmt" ) type employee struct { firstName string lastName string totalLeaves int leavesTaken int } func New(firstName string, lastName string, totalLeave int, leavesTaken int) employee { e := employee {firstName, lastName, totalLeave, leavesTaken} return e } func (e employee) LeavesRemaining() { fmt.Printf( "%s %s has %d leaves remaining" , e.firstName, e.lastName, (e.totalLeaves - e.leavesTaken)) } |
1 2 3 4 5 6 7 8 | //main.go文件<br>package main import "oop/employee" func main() { e := employee.New( "Sam" , "Adolf" , 30, 20) e.LeavesRemaining() } |
总结:Go 不支持类,但结构体能够很好地取代类,而以 New(parameters)
签名的方法可以替代构造器。
组合取代继承
Go 不支持继承,但它支持组合(Composition)。组合一般定义为“合并在一起”。汽车就是一个关于组合的例子:一辆汽车由车轮、引擎和其他各种部件组合在一起。
在 Go 中,通过在结构体内嵌套结构体,可以实现组合。
组合的典型例子就是博客帖子。每一个博客的帖子都有标题、内容和作者信息。使用组合可以很好地表示它们。通过学习本教程后面的内容,我们会知道如何实现组合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | package main import ( "fmt" ) type author struct { firstName string lastName string bio string } func (a author) fullName() string { return fmt.Sprintf( "%s %s" , a.firstName, a.lastName) } type post struct { title string content string author } func (p post) details() { fmt.Println( "Title: " , p.title) fmt.Println( "Content: " , p.content) fmt.Println( "Author: " , p.fullName()) fmt.Println( "Bio: " , p.bio) } func main() { author1 := author{ "Naveen" , "Ramanathan" , "Golang Enthusiast" , } post1 := post{ "Inheritance in Go" , "Go supports composition instead of inheritance" , author1, } post1.details() } |
1 2 3 4 | Title: Inheritance in Go Content: Go supports composition instead of inheritance Author: Naveen Ramanathan Bio: Golang Enthusiast |
结构体切片的嵌套
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | package main import ( "fmt" ) type author struct { firstName string lastName string bio string } func (a author) fullName() string { return fmt.Sprintf( "%s %s" , a.firstName, a.lastName) } type post struct { title string content string author } func (p post) details() { fmt.Println( "Title: " , p.title) fmt.Println( "Content: " , p.content) fmt.Println( "Author: " , p.fullName()) fmt.Println( "Bio: " , p.bio) } type website struct { posts []post } func (w website) contents() { fmt.Println( "Contents of Website\n" ) for _, v := range w.posts { v.details() fmt.Println() } } func main() { author1 := author{ "Naveen" , "Ramanathan" , "Golang Enthusiast" , } post1 := post{ "Inheritance in Go" , "Go supports composition instead of inheritance" , author1, } post2 := post{ "Struct instead of Classes in Go" , "Go does not support classes but methods can be added to structs" , author1, } post3 := post{ "Concurrency" , "Go is a concurrent language and not a parallel one" , author1, } w := website{ posts: []post{post1, post2, post3}, } w.contents() } |
在上面的主函数中,我们创建了一个作者 author1
,以及三个帖子 post1
、post2
和 post3
。我们最后通过嵌套三个帖子,在第 62 行创建了网站 w
,并在下一行显示内容。
程序会输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | Contents of Website Title: Inheritance in Go Content: Go supports composition instead of inheritance Author: Naveen Ramanathan Bio: Golang Enthusiast Title: Struct instead of Classes in Go Content: Go does not support classes but methods can be added to structs Author: Naveen Ramanathan Bio: Golang Enthusiast Title: Concurrency Content: Go is a concurrent language and not a parallel one Author: Naveen Ramanathan Bio: Golang Enthusiast |
使用接口实现多态
Go 通过接口来实现多态。在 Go 语言中,我们是隐式地实现接口。一个类型如果定义了接口所声明的全部方法,那它就实现了该接口。
1、多个类型可以实现同一个接口。
2、一个类型可以实现多个接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | package main import ( "fmt" ) type Income interface { calculate() int source() string } type FixedBilling struct { projectName string biddedAmount int } type TimeAndMaterial struct { projectName string noOfHours int hourlyRate int } func (fb FixedBilling) calculate() int { return fb.biddedAmount } func (fb FixedBilling) source() string { return fb.projectName } func (tm TimeAndMaterial) calculate() int { return tm.noOfHours * tm.hourlyRate } func (tm TimeAndMaterial) source() string { return tm.projectName } func calculateNetIncome(ic []Income) { var netincome int = 0 for _, income := range ic { fmt.Printf( "Income From %s = $%d\n" , income.source(), income.calculate()) netincome += income.calculate() } fmt.Printf( "Net income of organisation = $%d" , netincome) } func main() { project1 := FixedBilling{projectName: "Project 1" , biddedAmount: 5000} project2 := FixedBilling{projectName: "Project 2" , biddedAmount: 10000} project3 := TimeAndMaterial{projectName: "Project 3" , noOfHours: 160, hourlyRate: 25} incomeStreams := []Income{project1, project2, project3} calculateNetIncome(incomeStreams) } |
在上面的 main
函数中,我们创建了三个项目,有两个是 FixedBilling
类型,一个是 TimeAndMaterial
类型。接着我们创建了一个 Income
类型的切片,存放了这三个项目。由于这三个项目都实现了 Interface
接口,因此可以把这三个项目放入 Income
切片。最后我们将该切片作为参数,调用了 calculateNetIncome
函数,显示了项目不同的收益和收入来源。
1 2 3 4 | Income From Project 1 = $5000 Income From Project 2 = $10000 Income From Project 3 = $4000 Net income of organisation = $19000 |
refer:https://studygolang.com/articles/12681
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2018-11-06 Web轻量级扫描工具Skipfish